summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS11
-rw-r--r--ChangeLog69
-rw-r--r--HACKING5
-rw-r--r--Makefile.am38
-rw-r--r--Makefile.plugins10
-rw-r--r--Makefile.tools92
-rw-r--r--TODO26
-rwxr-xr-x[-rw-r--r--]android/Android.mk15
-rwxr-xr-x[-rw-r--r--]android/Makefile.am11
-rwxr-xr-x[-rw-r--r--]android/README31
-rwxr-xr-x[-rw-r--r--]android/a2dp-sink.c0
-rwxr-xr-x[-rw-r--r--]android/a2dp-sink.h0
-rwxr-xr-x[-rw-r--r--]android/a2dp.c0
-rwxr-xr-x[-rw-r--r--]android/a2dp.h0
-rwxr-xr-x[-rw-r--r--]android/audio-ipc-api.txt0
-rwxr-xr-x[-rw-r--r--]android/audio-msg.h0
-rwxr-xr-x[-rw-r--r--]android/avctp.c0
-rwxr-xr-x[-rw-r--r--]android/avctp.h0
-rwxr-xr-x[-rw-r--r--]android/avdtp.c9
-rwxr-xr-x[-rw-r--r--]android/avdtp.h0
-rwxr-xr-x[-rw-r--r--]android/avdtptest.c16
-rwxr-xr-x[-rw-r--r--]android/avrcp-lib.c0
-rwxr-xr-x[-rw-r--r--]android/avrcp-lib.h2
-rwxr-xr-x[-rw-r--r--]android/avrcp.c5
-rwxr-xr-x[-rw-r--r--]android/avrcp.h0
-rwxr-xr-x[-rw-r--r--]android/bas.c0
-rwxr-xr-x[-rw-r--r--]android/bas.h0
-rwxr-xr-x[-rw-r--r--]android/bluetooth.c17
-rwxr-xr-x[-rw-r--r--]android/bluetooth.h0
-rwxr-xr-x[-rw-r--r--]android/bluetoothd-snoop.c9
-rwxr-xr-x[-rw-r--r--]android/bluetoothd-wrapper.c0
-rwxr-xr-x[-rw-r--r--]android/bluetoothd.te0
-rwxr-xr-x[-rw-r--r--]android/bluetoothd_snoop.te0
-rw-r--r--android/client/if-bt.c9
-rw-r--r--android/client/if-gatt.c58
-rw-r--r--android/client/if-hl.c4
-rwxr-xr-x[-rw-r--r--]android/cts.txt0
-rwxr-xr-x[-rw-r--r--]android/dis.c0
-rwxr-xr-x[-rw-r--r--]android/dis.h0
-rwxr-xr-x[-rw-r--r--]android/gatt.c347
-rwxr-xr-x[-rw-r--r--]android/gatt.h0
-rwxr-xr-x[-rw-r--r--]android/hal-a2dp-sink.c0
-rwxr-xr-x[-rw-r--r--]android/hal-a2dp.c0
-rwxr-xr-x[-rw-r--r--]android/hal-audio-aptx.c0
-rwxr-xr-x[-rw-r--r--]android/hal-audio-sbc.c0
-rwxr-xr-x[-rw-r--r--]android/hal-audio.c0
-rwxr-xr-x[-rw-r--r--]android/hal-audio.h0
-rwxr-xr-x[-rw-r--r--]android/hal-avrcp-ctrl.c0
-rwxr-xr-x[-rw-r--r--]android/hal-avrcp.c0
-rwxr-xr-x[-rw-r--r--]android/hal-bluetooth.c6
-rwxr-xr-x[-rw-r--r--]android/hal-gatt.c0
-rwxr-xr-x[-rw-r--r--]android/hal-handsfree-client.c0
-rwxr-xr-x[-rw-r--r--]android/hal-handsfree.c12
-rwxr-xr-x[-rw-r--r--]android/hal-health.c0
-rwxr-xr-x[-rw-r--r--]android/hal-hidhost.c0
-rwxr-xr-x[-rw-r--r--]android/hal-ipc-api.txt8
-rwxr-xr-x[-rw-r--r--]android/hal-ipc.c0
-rwxr-xr-x[-rw-r--r--]android/hal-ipc.h0
-rwxr-xr-x[-rw-r--r--]android/hal-log.h0
-rwxr-xr-x[-rw-r--r--]android/hal-map-client.c0
-rwxr-xr-x[-rw-r--r--]android/hal-msg.h6
-rwxr-xr-x[-rw-r--r--]android/hal-pan.c0
-rwxr-xr-x[-rw-r--r--]android/hal-sco.c0
-rwxr-xr-x[-rw-r--r--]android/hal-socket.c0
-rwxr-xr-x[-rw-r--r--]android/hal-utils.c0
-rwxr-xr-x[-rw-r--r--]android/hal-utils.h0
-rwxr-xr-x[-rw-r--r--]android/hal.h0
-rwxr-xr-x[-rw-r--r--]android/handsfree-client.c14
-rwxr-xr-x[-rw-r--r--]android/handsfree-client.h0
-rwxr-xr-x[-rw-r--r--]android/handsfree.c18
-rwxr-xr-x[-rw-r--r--]android/handsfree.h0
-rwxr-xr-x[-rw-r--r--]android/health.c67
-rwxr-xr-x[-rw-r--r--]android/health.h0
-rwxr-xr-x[-rw-r--r--]android/hidhost.c4
-rwxr-xr-x[-rw-r--r--]android/hidhost.h0
-rwxr-xr-x[-rw-r--r--]android/hog.c0
-rwxr-xr-x[-rw-r--r--]android/hog.h0
-rwxr-xr-x[-rw-r--r--]android/init.bluetooth.rc0
-rwxr-xr-x[-rw-r--r--]android/ipc-common.h0
-rwxr-xr-x[-rw-r--r--]android/ipc-tester.c0
-rwxr-xr-x[-rw-r--r--]android/ipc.c0
-rwxr-xr-x[-rw-r--r--]android/ipc.h0
-rwxr-xr-x[-rw-r--r--]android/log.c2
-rwxr-xr-x[-rw-r--r--]android/main.c0
-rwxr-xr-x[-rw-r--r--]android/map-client.c0
-rwxr-xr-x[-rw-r--r--]android/map-client.h0
-rwxr-xr-x[-rw-r--r--]android/pan.c8
-rwxr-xr-x[-rw-r--r--]android/pan.h0
-rwxr-xr-x[-rw-r--r--]android/pics-a2dp.txt10
-rwxr-xr-x[-rw-r--r--]android/pics-avctp.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-avdtp.txt14
-rwxr-xr-x[-rw-r--r--]android/pics-avrcp.txt4
-rwxr-xr-x[-rw-r--r--]android/pics-bnep.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-did.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-dis.txt6
-rwxr-xr-x[-rw-r--r--]android/pics-gap.txt11
-rwxr-xr-x[-rw-r--r--]android/pics-gatt.txt15
-rwxr-xr-x[-rw-r--r--]android/pics-gavdp.txt15
-rwxr-xr-x[-rw-r--r--]android/pics-hdp.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-hfp.txt4
-rwxr-xr-x[-rw-r--r--]android/pics-hid.txt63
-rwxr-xr-x[-rw-r--r--]android/pics-hogp.txt73
-rwxr-xr-x[-rw-r--r--]android/pics-hsp.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-iopt.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-l2cap.txt25
-rwxr-xr-x[-rw-r--r--]android/pics-map.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-mcap.txt4
-rwxr-xr-x[-rw-r--r--]android/pics-mps.txt82
-rwxr-xr-x[-rw-r--r--]android/pics-opp.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-pan.txt2
-rwxr-xr-x[-rw-r--r--]android/pics-pbap.txt8
-rwxr-xr-x[-rw-r--r--]android/pics-rfcomm.txt8
-rwxr-xr-x[-rw-r--r--]android/pics-scpp.txt4
-rwxr-xr-x[-rw-r--r--]android/pics-sdp.txt8
-rwxr-xr-x[-rw-r--r--]android/pics-sm.txt23
-rwxr-xr-x[-rw-r--r--]android/pics-spp.txt12
-rwxr-xr-x[-rw-r--r--]android/pixit-a2dp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-avctp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-avdtp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-avrcp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-bnep.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-did.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-dis.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-gap.txt8
-rwxr-xr-x[-rw-r--r--]android/pixit-gatt.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-gavdp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-hdp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-hfp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-hid.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-hogp.txt4
-rwxr-xr-x[-rw-r--r--]android/pixit-hsp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-iopt.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-l2cap.txt14
-rwxr-xr-x[-rw-r--r--]android/pixit-map.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-mcap.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-mps.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-opp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-pan.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-pbap.txt3
-rwxr-xr-x[-rw-r--r--]android/pixit-rfcomm.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-scpp.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-sdp.txt4
-rwxr-xr-x[-rw-r--r--]android/pixit-sm.txt2
-rwxr-xr-x[-rw-r--r--]android/pixit-spp.txt2
-rwxr-xr-x[-rw-r--r--]android/pts-a2dp.txt33
-rwxr-xr-x[-rw-r--r--]android/pts-avctp.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-avdtp.txt8
-rwxr-xr-x[-rw-r--r--]android/pts-avrcp.txt68
-rwxr-xr-x[-rw-r--r--]android/pts-bnep.txt21
-rwxr-xr-x[-rw-r--r--]android/pts-did.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-dis.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-gap.txt68
-rwxr-xr-x[-rw-r--r--]android/pts-gatt.txt1061
-rwxr-xr-x[-rw-r--r--]android/pts-gavdp.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-hdp.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-hfp.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-hid.txt7
-rwxr-xr-x[-rw-r--r--]android/pts-hogp.txt8
-rwxr-xr-x[-rw-r--r--]android/pts-hsp.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-iopt.txt8
-rwxr-xr-x[-rw-r--r--]android/pts-l2cap.txt57
-rwxr-xr-x[-rw-r--r--]android/pts-map.txt11
-rwxr-xr-x[-rw-r--r--]android/pts-mcap.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-mps.txt10
-rwxr-xr-x[-rw-r--r--]android/pts-opp.txt12
-rwxr-xr-x[-rw-r--r--]android/pts-pan.txt49
-rwxr-xr-x[-rw-r--r--]android/pts-pbap.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-rfcomm.txt14
-rwxr-xr-x[-rw-r--r--]android/pts-scpp.txt6
-rwxr-xr-x[-rw-r--r--]android/pts-sdp.txt8
-rwxr-xr-x[-rw-r--r--]android/pts-sm.txt36
-rwxr-xr-x[-rw-r--r--]android/pts-spp.txt13
-rwxr-xr-x[-rw-r--r--]android/sco-ipc-api.txt0
-rwxr-xr-x[-rw-r--r--]android/sco-msg.h0
-rwxr-xr-x[-rw-r--r--]android/sco.c0
-rwxr-xr-x[-rw-r--r--]android/sco.h0
-rwxr-xr-x[-rw-r--r--]android/scpp.c0
-rwxr-xr-x[-rw-r--r--]android/scpp.h0
-rwxr-xr-x[-rw-r--r--]android/socket-api.txt0
-rwxr-xr-x[-rw-r--r--]android/socket.c0
-rwxr-xr-x[-rw-r--r--]android/socket.h0
-rwxr-xr-x[-rw-r--r--]android/system-emulator.c0
-rwxr-xr-x[-rw-r--r--]android/test-ipc.c0
-rwxr-xr-x[-rw-r--r--]android/tester-a2dp.c7
-rwxr-xr-x[-rw-r--r--]android/tester-avrcp.c7
-rwxr-xr-x[-rw-r--r--]android/tester-bluetooth.c15
-rwxr-xr-x[-rw-r--r--]android/tester-gatt.c7
-rwxr-xr-x[-rw-r--r--]android/tester-hdp.c7
-rwxr-xr-x[-rw-r--r--]android/tester-hidhost.c7
-rwxr-xr-x[-rw-r--r--]android/tester-main.c49
-rwxr-xr-x[-rw-r--r--]android/tester-main.h0
-rwxr-xr-x[-rw-r--r--]android/tester-map-client.c7
-rwxr-xr-x[-rw-r--r--]android/tester-pan.c7
-rwxr-xr-x[-rw-r--r--]android/tester-socket.c7
-rwxr-xr-x[-rw-r--r--]android/utils.h0
-rw-r--r--attrib/gatt-service.c30
-rw-r--r--attrib/gatt-service.h6
-rw-r--r--attrib/gatt.c17
-rw-r--r--attrib/gatt.h2
-rw-r--r--attrib/gattrib.c15
-rw-r--r--attrib/gattrib.h5
-rw-r--r--attrib/gatttool.c2
-rw-r--r--attrib/interactive.c2
-rw-r--r--[-rwxr-xr-x]bootstrap-configure1
-rw-r--r--client/gatt.c44
-rw-r--r--client/main.c263
-rw-r--r--configure.ac16
-rw-r--r--doc/adapter-api.txt12
-rw-r--r--doc/advertising-api.txt5
-rw-r--r--doc/agent-api.txt2
-rw-r--r--doc/coding-style.txt2
-rw-r--r--doc/device-api.txt24
-rw-r--r--doc/gatt-api.txt33
-rw-r--r--doc/maintainer-guidelines.txt2
-rw-r--r--doc/media-api.txt24
-rw-r--r--doc/mgmt-api.txt258
-rw-r--r--doc/pics-opp.txt187
-rw-r--r--doc/pixit-opp.txt27
-rw-r--r--doc/pts-opp.txt119
-rw-r--r--doc/settings-storage.txt38
-rw-r--r--doc/supported-features.txt9
-rw-r--r--doc/test-coverage.txt15
-rw-r--r--doc/test-runner.txt54
-rw-r--r--emulator/btdev.c418
-rw-r--r--emulator/btdev.h4
-rw-r--r--emulator/bthost.c71
-rw-r--r--emulator/bthost.h5
-rw-r--r--emulator/hciemu.c16
-rw-r--r--emulator/hciemu.h4
-rw-r--r--emulator/le.c110
-rw-r--r--emulator/phy.h2
-rw-r--r--emulator/server.c7
-rw-r--r--gdbus/client.c6
-rw-r--r--gdbus/gdbus.h20
-rw-r--r--gdbus/mainloop.c1
-rw-r--r--gdbus/object.c34
-rw-r--r--gdbus/watch.c50
-rw-r--r--gobex/gobex-apparam.c7
-rw-r--r--gobex/gobex-apparam.h4
-rw-r--r--gobex/gobex-transfer.c1
-rw-r--r--lib/bluetooth.c486
-rw-r--r--lib/bluetooth.h10
-rw-r--r--lib/bnep.h2
-rw-r--r--lib/hci.c36
-rw-r--r--[-rwxr-xr-x]lib/hci.h1
-rw-r--r--lib/hci_lib.h3
-rw-r--r--[-rwxr-xr-x]lib/mgmt.h28
-rw-r--r--lib/sdp.c9
-rw-r--r--lib/uuid.c65
-rw-r--r--lib/uuid.h6
-rw-r--r--monitor/a2dp.c638
-rw-r--r--monitor/a2dp.h26
-rw-r--r--monitor/analyze.c15
-rw-r--r--monitor/avctp.c781
-rw-r--r--monitor/avdtp.c787
-rw-r--r--monitor/avdtp.h24
-rw-r--r--monitor/bnep.c482
-rw-r--r--monitor/bnep.h25
-rw-r--r--monitor/broadcom.c251
-rw-r--r--monitor/broadcom.h32
-rw-r--r--monitor/bt.h60
-rw-r--r--monitor/btsnoop.c554
-rw-r--r--monitor/btsnoop.h68
-rw-r--r--monitor/control.c76
-rw-r--r--monitor/display.h5
-rw-r--r--monitor/hcidump.c10
-rw-r--r--monitor/intel.c932
-rw-r--r--monitor/intel.h31
-rw-r--r--monitor/l2cap.c195
-rw-r--r--monitor/l2cap.h17
-rw-r--r--monitor/ll.c65
-rw-r--r--monitor/ll.h4
-rw-r--r--monitor/lmp.c136
-rw-r--r--monitor/lmp.h2
-rw-r--r--monitor/main.c9
-rw-r--r--monitor/packet.c616
-rw-r--r--monitor/packet.h32
-rw-r--r--monitor/rfcomm.c6
-rw-r--r--monitor/uuid.c184
-rw-r--r--monitor/vendor.h19
-rw-r--r--obexd.manifest26
-rw-r--r--obexd/client/manager.c1
-rw-r--r--obexd/client/mns-tizen.c13
-rw-r--r--obexd/client/pbap.c8
-rw-r--r--obexd/client/session.c85
-rw-r--r--obexd/plugins/opp.c20
-rw-r--r--obexd/plugins/pbap.c21
-rw-r--r--obexd/plugins/phonebook-dummy.c5
-rwxr-xr-x[-rw-r--r--]obexd/src/log.c2
-rwxr-xr-x[-rw-r--r--]obexd/src/log.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/main.c6
-rwxr-xr-x[-rw-r--r--]obexd/src/manager.c2
-rwxr-xr-x[-rw-r--r--]obexd/src/manager.h2
-rwxr-xr-x[-rw-r--r--]obexd/src/map_ap.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/mimetype.c0
-rwxr-xr-x[-rw-r--r--]obexd/src/mimetype.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/obex-priv.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/obex.c12
-rwxr-xr-x[-rw-r--r--]obexd/src/obex.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/obex.service.in0
-rwxr-xr-x[-rw-r--r--]obexd/src/obexd.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/org.bluez.obex.service0
-rwxr-xr-x[-rw-r--r--]obexd/src/plugin.c0
-rwxr-xr-x[-rw-r--r--]obexd/src/plugin.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/server.c0
-rwxr-xr-x[-rw-r--r--]obexd/src/server.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/service.c0
-rwxr-xr-x[-rw-r--r--]obexd/src/service.h0
-rwxr-xr-x[-rw-r--r--]obexd/src/transport.c0
-rwxr-xr-x[-rw-r--r--]obexd/src/transport.h0
-rw-r--r--[-rwxr-xr-x]packaging/baselibs.conf0
-rw-r--r--[-rwxr-xr-x]packaging/bluetooth.modprobe0
-rw-r--r--[-rwxr-xr-x]packaging/bluetooth.sh0
-rw-r--r--[-rwxr-xr-x]packaging/bluetooth.sysconfig0
-rw-r--r--[-rwxr-xr-x]packaging/bluez-coldplug.init0
-rw-r--r--[-rwxr-xr-x]packaging/bluez.changes0
-rw-r--r--[-rwxr-xr-x]packaging/bluez.manifest0
-rw-r--r--packaging/bluez.spec3
-rw-r--r--[-rwxr-xr-x]packaging/obex.sh0
-rw-r--r--peripheral/attach.c144
-rw-r--r--peripheral/attach.h25
-rw-r--r--peripheral/efivars.c132
-rw-r--r--peripheral/efivars.h33
-rw-r--r--peripheral/gap.c551
-rw-r--r--peripheral/gap.h29
-rw-r--r--peripheral/gatt.c318
-rw-r--r--peripheral/gatt.h30
-rw-r--r--peripheral/log.c56
-rw-r--r--peripheral/log.h25
-rw-r--r--peripheral/main.c247
-rw-r--r--plugins/policy.c124
-rw-r--r--profiles/audio/a2dp-codecs.h8
-rw-r--r--profiles/audio/a2dp.c139
-rw-r--r--profiles/audio/a2dp.h6
-rw-r--r--profiles/audio/avctp.c59
-rw-r--r--profiles/audio/avctp.h3
-rw-r--r--profiles/audio/avdtp.c159
-rw-r--r--profiles/audio/avrcp.c681
-rw-r--r--profiles/audio/avrcp.h7
-rw-r--r--profiles/audio/control.c67
-rw-r--r--profiles/audio/control.h2
-rw-r--r--profiles/audio/media.c66
-rw-r--r--profiles/audio/player.c142
-rw-r--r--profiles/audio/player.h12
-rw-r--r--profiles/audio/sink.c8
-rw-r--r--profiles/audio/source.c8
-rw-r--r--profiles/audio/transport.c17
-rw-r--r--profiles/battery/bas.c340
-rw-r--r--profiles/battery/bas.h32
-rw-r--r--profiles/deviceinfo/deviceinfo.c163
-rw-r--r--profiles/deviceinfo/dis.c293
-rw-r--r--profiles/deviceinfo/dis.h39
-rw-r--r--profiles/gap/gas.c42
-rw-r--r--profiles/input/hog-lib.c1550
-rw-r--r--profiles/input/hog-lib.h41
-rw-r--r--profiles/input/hog.c934
-rw-r--r--profiles/input/suspend-none.c42
-rw-r--r--profiles/network/bnep.c55
-rw-r--r--profiles/network/connection.c15
-rw-r--r--profiles/network/server.c5
-rw-r--r--profiles/scanparam/scan.c256
-rw-r--r--profiles/scanparam/scpp.c355
-rw-r--r--profiles/scanparam/scpp.h35
-rw-r--r--src/adapter.c2080
-rw-r--r--src/adapter.h13
-rw-r--r--src/adapter_le_vsc_features.c114
-rw-r--r--src/adapter_le_vsc_features.h102
-rw-r--r--src/advertising.c507
-rw-r--r--src/agent.c2
-rw-r--r--src/attrib-server.c67
-rw-r--r--src/backtrace.c135
-rw-r--r--src/backtrace.h35
-rw-r--r--src/bluetooth.conf3
-rw-r--r--src/dbus-common.c27
-rw-r--r--src/dbus-common.h5
-rw-r--r--src/device.c1886
-rw-r--r--src/device.h32
-rw-r--r--src/eir.c84
-rw-r--r--src/eir.h20
-rw-r--r--src/gatt-client.c351
-rw-r--r--src/gatt-client.h7
-rw-r--r--src/gatt-database.c975
-rw-r--r--src/log.c210
-rw-r--r--src/log.h24
-rw-r--r--src/main.c62
-rw-r--r--src/profile.c147
-rw-r--r--src/profile.h1
-rw-r--r--src/sdp-xml.c1
-rw-r--r--src/sdpd-server.c3
-rw-r--r--src/service.c42
-rw-r--r--src/shared/ad.c658
-rw-r--r--src/shared/ad.h90
-rw-r--r--src/shared/att-types.h49
-rw-r--r--src/shared/att.c173
-rw-r--r--src/shared/att.h6
-rw-r--r--src/shared/btsnoop.c112
-rw-r--r--src/shared/btsnoop.h56
-rw-r--r--src/shared/crypto.c2
-rw-r--r--src/shared/gap.c7
-rw-r--r--src/shared/gatt-client.c1014
-rw-r--r--src/shared/gatt-client.h25
-rw-r--r--src/shared/gatt-db.c91
-rw-r--r--src/shared/gatt-helpers.c37
-rw-r--r--src/shared/gatt-server.c184
-rw-r--r--src/shared/hci-crypto.c6
-rw-r--r--src/shared/hci.c29
-rw-r--r--src/shared/hfp.c40
-rw-r--r--src/shared/io-mainloop.c3
-rw-r--r--src/shared/mgmt.c108
-rw-r--r--src/shared/queue.c48
-rw-r--r--src/shared/queue.h1
-rw-r--r--src/shared/ringbuf.c3
-rw-r--r--src/shared/tester.c23
-rw-r--r--src/shared/timeout-mainloop.c3
-rw-r--r--src/shared/uhid.c8
-rw-r--r--src/shared/util.c16
-rw-r--r--src/shared/util.h19
-rw-r--r--test/example-advertisement178
-rw-r--r--test/example-gatt-client218
-rw-r--r--test/example-gatt-server591
-rw-r--r--[-rwxr-xr-x]test/exchange-business-cards0
-rw-r--r--[-rwxr-xr-x]test/ftp-client8
-rw-r--r--[-rwxr-xr-x]test/get-managed-objects0
-rw-r--r--[-rwxr-xr-x]test/get-obex-capabilities0
-rw-r--r--[-rwxr-xr-x]test/list-devices0
-rw-r--r--[-rwxr-xr-x]test/list-folders0
-rw-r--r--[-rwxr-xr-x]test/map-client0
-rw-r--r--[-rwxr-xr-x]test/monitor-bluetooth0
-rw-r--r--[-rwxr-xr-x]test/opp-client0
-rw-r--r--[-rwxr-xr-x]test/simple-agent0
-rw-r--r--[-rwxr-xr-x]test/simple-endpoint0
-rw-r--r--[-rwxr-xr-x]test/simple-obex-agent0
-rw-r--r--[-rwxr-xr-x]test/simple-player1
-rw-r--r--[-rwxr-xr-x]test/test-adapter0
-rw-r--r--[-rwxr-xr-x]test/test-alert0
-rw-r--r--[-rwxr-xr-x]test/test-cyclingspeed0
-rw-r--r--[-rwxr-xr-x]test/test-device0
-rw-r--r--[-rwxr-xr-x]test/test-discovery40
-rw-r--r--test/test-gatt-profile60
-rw-r--r--[-rwxr-xr-x]test/test-health0
-rw-r--r--[-rwxr-xr-x]test/test-health-sink0
-rw-r--r--[-rwxr-xr-x]test/test-heartrate0
-rw-r--r--[-rwxr-xr-x]test/test-hfp0
-rw-r--r--[-rwxr-xr-x]test/test-manager0
-rw-r--r--[-rwxr-xr-x]test/test-nap17
-rw-r--r--[-rwxr-xr-x]test/test-network0
-rw-r--r--[-rwxr-xr-x]test/test-profile0
-rw-r--r--[-rwxr-xr-x]test/test-proximity0
-rw-r--r--[-rwxr-xr-x]test/test-sap-server0
-rw-r--r--[-rwxr-xr-x]test/test-thermometer0
-rw-r--r--tools/avinfo.c44
-rw-r--r--tools/bccmd.c43
-rw-r--r--tools/bnep-tester.c309
-rw-r--r--tools/bneptest.c10
-rw-r--r--tools/btattach.153
-rw-r--r--tools/btattach.c58
-rw-r--r--tools/btgatt-client.c28
-rw-r--r--tools/btgatt-server.c2
-rw-r--r--tools/btmgmt.c318
-rw-r--r--tools/btproxy.c238
-rw-r--r--tools/btsnoop.c51
-rw-r--r--tools/check-selftest.c71
-rw-r--r--tools/create-image.c205
-rw-r--r--tools/csr.h2
-rw-r--r--tools/eddystone.c319
-rw-r--r--tools/gatt-service.c4
-rw-r--r--tools/hci-tester.c280
-rw-r--r--tools/hciattach.c48
-rw-r--r--tools/hciattach.h6
-rw-r--r--tools/hciattach_sprd.c27
-rw-r--r--tools/hciconfig.c20
-rw-r--r--tools/hcidump.c22
-rw-r--r--tools/hcitool.c63
-rw-r--r--tools/l2cap-tester.c512
-rw-r--r--tools/l2test.c60
-rw-r--r--tools/mgmt-tester.c1087
-rw-r--r--tools/mpris-proxy.c2
-rw-r--r--tools/nokfw.c247
-rw-r--r--tools/obex-client-tool.c5
-rw-r--r--tools/obexctl.c37
-rw-r--r--tools/parse_companies.pl59
-rw-r--r--tools/parser/att.c92
-rw-r--r--tools/parser/avctp.c4
-rw-r--r--tools/parser/avdtp.c74
-rw-r--r--tools/parser/avrcp.c290
-rw-r--r--tools/parser/bnep.c50
-rw-r--r--tools/parser/bpa.c16
-rw-r--r--tools/parser/capi.c8
-rw-r--r--tools/parser/cmtp.c6
-rw-r--r--tools/parser/csr.c6
-rw-r--r--tools/parser/ericsson.c2
-rw-r--r--tools/parser/hci.c74
-rw-r--r--tools/parser/hcrp.c12
-rw-r--r--tools/parser/hidp.c2
-rw-r--r--tools/parser/lmp.c6
-rw-r--r--tools/parser/obex.c24
-rw-r--r--tools/parser/parser.h14
-rw-r--r--tools/parser/ppp.c8
-rw-r--r--tools/parser/sap.c24
-rw-r--r--tools/parser/sdp.c50
-rw-r--r--tools/parser/smp.c34
-rw-r--r--tools/rctest.c17
-rw-r--r--tools/rfcomm-tester.c2
-rw-r--r--tools/sco-tester.c1
-rw-r--r--tools/sdptool.c40
-rw-r--r--tools/smp-tester.c11
-rw-r--r--tools/test-runner.c869
-rw-r--r--tools/userchan-tester.c334
-rw-r--r--tools/valgrind.supp27
-rw-r--r--unit/test-avrcp.c75
-rw-r--r--unit/test-crc.c37
-rw-r--r--unit/test-crypto.c35
-rw-r--r--unit/test-ecc.c99
-rw-r--r--unit/test-eir.c143
-rw-r--r--unit/test-gatt.c501
-rw-r--r--unit/test-gattrib.c2
-rw-r--r--unit/test-gdbus-client.c284
-rw-r--r--unit/test-gobex-header.c2
-rw-r--r--unit/test-hfp.c91
-rw-r--r--unit/test-hog.c4
-rw-r--r--unit/test-lib.c106
-rw-r--r--unit/test-queue.c55
-rw-r--r--unit/test-ringbuf.c31
-rw-r--r--unit/test-sdp.c91
-rw-r--r--unit/test-textfile.c49
-rw-r--r--unit/test-uhid.c62
-rw-r--r--unit/test-uuid.c56
527 files changed, 30281 insertions, 7918 deletions
diff --git a/AUTHORS b/AUTHORS
index 7c20697a..16fb14cb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -57,11 +57,11 @@ Brian Gix <bgix@codeaurora.org>
Andre Guedes <andre.guedes@openbossa.org>
Sheldon Demario <sheldon.demario@openbossa.org>
Lucas De Marchi <lucas.demarchi@profusion.mobi>
-Szymon Janc <szymon.janc@tieto.com>
+Szymon Janc <szymon.janc@codecoup.pl>
Syam Sidhardhan <s.syam@samsung.com>
Paulo Alcantara <pcacjr@gmail.com>
Jefferson Delfes <jefferson.delfes@openbossa.org>
-Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com>
+Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
Eder Ruiz Maria <eder.ruiz@openbossa.org>
Mikel Astiz <mikel.astiz@bmw-carit.de>
Chan-yeol Park <chanyeol.park@samsung.com>
@@ -85,7 +85,7 @@ Scott James Remnant <scott@netsplit.com>
Jakub Tyszkowski <jakub.tyszkowski@tieto.com>
Grzegorz Kołodziejczyk <grzegorz.kolodziejczyk@tieto.com>
Marcin Krąglak <marcin.kraglak@tieto.com>
-Łukasz Rymanowski <lukasz.rymanowski@tieto.com>
+Łukasz Rymanowski <lukasz.rymanowski@codecoup.pl>
Jerzy Kasenberg <jerzy.kasenberg@tieto.com>
Arman Uguray <armansito@chromium.org>
Artem Rakhov <arakhov@chromium.org>
@@ -94,3 +94,8 @@ David Herrmann <dh.herrmann@gmail.com>
Jacob Siverskog <jacob@teenageengineering.com>
Sebastian Chłąd <sebastian.chlad@tieto.com>
Alex Gal <a.gal@miip.ca>
+Loic Poulain <loic.poulain@intel.com>
+Gowtham Anandha Babu <gowtham.ab@samsung.com>
+Bharat Panda <bharat.panda@samsung.com>
+Marie Janssen <jamuraa@chromium.org>
+Jaganath Kanakkassery <jaganath.k@samsung.com>
diff --git a/ChangeLog b/ChangeLog
index 8aed8be7..c7a4fc00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,72 @@
+ver 5.37:
+ Fix issue with registering external profiles.
+ Fix issue with connecting external profiles.
+ Fix issue with GATT service changed handling.
+ Fix issue with not emitting GattServices update.
+ Convert to unified HID over GATT profile support.
+ Convert to KeyboardDisplay as default IO capability.
+ Install btattach utility by default.
+
+ver 5.36:
+ Fix issue with PBAP headers for size query.
+ Fix issue with AVRCP current player handling.
+ Fix issue with device information handling.
+ Fix issue with device disconnect handling.
+ Fix issue with duplicate connect handling.
+ Fix issue with attribute claiming for drivers.
+
+ver 5.35:
+ Fix issue with connected devices after discovery.
+ Fix issue with profile support and LTK loading.
+ Fix issue with AVRCP events for volume control.
+ Fix issue with OBEX session owner handling.
+ Fix issue with HID over GATT setup failures.
+ Fix issue with GATT notification registration.
+ Fix issue with GATT cache validation feature.
+ Add support for persistent GATT database.
+ Add support for controller enabling option.
+
+ver 5.34:
+ Fix issue with GATT profiles and auto-connect.
+ Fix issue with missing GoepL2CapPsm SDP data.
+ Fix issue with suspending AVDTP endpoints.
+ Fix issue with audio service state on disconnect.
+ Add support for AVRCP Set Addressed Player feature.
+ Add support for AVRCP Get Folder Items feature.
+ Add support for Android 5.1 HFP WBS callbacks.
+
+ver 5.33:
+ Fix issue with memory leak in GATT database.
+ Fix issue with AVDTP set configuration handling.
+ Fix issue with AVDTP discover procedure.
+ Fix issue with not emitting Paired property.
+
+ver 5.32:
+ Fix issue with OPP GET request path handling.
+ Fix issue with ATT information request errors.
+ Fix issue with advertising instance numbers.
+ Fix issue with overwriting SDP record cache.
+ Fix issue with new connections during disconnect.
+ Add support for GATT security auto-elevation.
+
+ver 5.31:
+ Fix issue with crash in networking interface.
+ Fix issue with crash when creating endless GATT loops.
+ Fix issue with memory leak when connecting services.
+ Fix issue with memory leak creating new D-Bus proxy.
+ Fix issue with profile connections from remote devices.
+ Fix issue with GATT over BR/EDR and MTU notification.
+ Fix issue with HID and dual mode remote devices.
+ Fix issue with handling A2DP vendor codec setup.
+ Fix issue with AVRCP and syncing player state.
+ Fix issue with GATT secondary discovery handling.
+ Fix issue with wrong characteristic allocation.
+ Add support for handling BNEP setup response.
+ Add support for setting GATT database security flags.
+ Add support for setting discovery filters interface.
+ Add support for user controlled advertising interface.
+ Update Android qualification documentation to PTS 6.1 release.
+
ver 5.30:
Fix compilation error in C++ due to inline function.
Fix issue with missing storage of device information.
diff --git a/HACKING b/HACKING
index ffca598d..a8fb403e 100644
--- a/HACKING
+++ b/HACKING
@@ -89,8 +89,9 @@ automatically includes this option.
# sudo ./src/bluetoothd -n -d
Run daemon with valgrind
- # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes
- --show-possibly-lost=no --leak-check=full ./src/bluetoothd -n -d
+ # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes \
+ --show-possibly-lost=no --leak-check=full --suppressions=./tools/valgrind.supp \
+ ./src/bluetoothd -n -d
For production installations or distribution packaging it is important that
the "--enable-maintainer-mode" option is NOT used.
diff --git a/Makefile.am b/Makefile.am
index f6c4ac83..39de3397 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -80,7 +80,7 @@ include_HEADERS += $(lib_headers)
lib_LTLIBRARIES += lib/libbluetooth.la
lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:3:18
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:10:18
lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
endif
@@ -111,6 +111,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
src/shared/uhid.h src/shared/uhid.c \
src/shared/pcap.h src/shared/pcap.c \
src/shared/btsnoop.h src/shared/btsnoop.c \
+ src/shared/ad.h src/shared/ad.c \
src/shared/att-types.h \
src/shared/att.h src/shared/att.c \
src/shared/gatt-helpers.h src/shared/gatt-helpers.c \
@@ -162,6 +163,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
$(attrib_sources) $(btio_sources) \
src/bluetooth.ver \
src/main.c src/log.h src/log.c \
+ src/backtrace.h src/backtrace.c \
src/systemd.h src/systemd.c \
src/rfkill.c src/hcid.h src/sdpd.h \
src/sdpd-server.c src/sdpd-request.c \
@@ -182,8 +184,6 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src/adapter_le_vsc_features.h src/adapter_le_vsc_features.c \
src/profile.h src/profile.c \
src/service.h src/service.c \
- src/gatt-dbus.h src/gatt-dbus.c \
- src/gatt.h src/gatt.c \
src/gatt-client.h src/gatt-client.c \
src/device.h src/device.c src/attio.h \
src/dbus-common.c src/dbus-common.h \
@@ -191,7 +191,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src_bluetoothd_LDADD = lib/libbluetooth-internal.la \
gdbus/libgdbus-internal.la \
src/libshared-glib.la \
- @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+ @BACKTRACE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
-Wl,--version-script=$(srcdir)/src/bluetooth.ver
@@ -247,7 +247,9 @@ endif
EXTRA_DIST += $(test_scripts)
EXTRA_DIST += doc/assigned-numbers.txt doc/supported-features.txt \
- doc/test-coverage.txt doc/settings-storage.txt
+ doc/test-coverage.txt \
+ doc/test-runner.txt \
+ doc/settings-storage.txt
EXTRA_DIST += doc/mgmt-api.txt \
doc/adapter-api.txt doc/device-api.txt \
@@ -263,6 +265,9 @@ EXTRA_DIST += doc/alert-api.txt \
EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt
+EXTRA_DIST += doc/pics-opp.txt doc/pixit-opp.txt \
+ doc/pts-opp.txt
+
EXTRA_DIST += tools/magic.btsnoop
AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@
@@ -273,22 +278,24 @@ AM_CPPFLAGS = -I$(builddir)/lib
unit_tests += unit/test-eir
unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/uuid-helper.c
-unit_test_eir_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_test_eir_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \
+ @GLIB_LIBS@
unit_tests += unit/test-uuid
unit_test_uuid_SOURCES = unit/test-uuid.c
-unit_test_uuid_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_test_uuid_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \
+ @GLIB_LIBS@
unit_tests += unit/test-textfile
unit_test_textfile_SOURCES = unit/test-textfile.c src/textfile.h src/textfile.c
-unit_test_textfile_LDADD = @GLIB_LIBS@
+unit_test_textfile_LDADD = src/libshared-glib.la @GLIB_LIBS@
unit_tests += unit/test-crc
unit_test_crc_SOURCES = unit/test-crc.c monitor/crc.h monitor/crc.c
-unit_test_crc_LDADD = @GLIB_LIBS@
+unit_test_crc_LDADD = src/libshared-glib.la @GLIB_LIBS@
unit_tests += unit/test-crypto
@@ -359,7 +366,7 @@ unit_tests += unit/test-gdbus-client
unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \
- @GLIB_LIBS@ @DBUS_LIBS@
+ src/libshared-glib.la @GLIB_LIBS@ @DBUS_LIBS@
unit_tests += unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
unit/test-gobex-transfer unit/test-gobex-apparam
@@ -387,7 +394,8 @@ unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
unit_tests += unit/test-lib
unit_test_lib_SOURCES = unit/test-lib.c
-unit_test_lib_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_test_lib_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la @GLIB_LIBS@
unit_tests += unit/test-gatt
@@ -399,10 +407,10 @@ unit_tests += unit/test-hog
unit_test_hog_SOURCES = unit/test-hog.c \
$(btio_sources) \
- android/hog.h android/hog.c \
- android/scpp.h android/scpp.c \
- android/bas.h android/bas.c \
- android/dis.h android/dis.c \
+ profiles/input/hog-lib.h profiles/input/hog-lib.c \
+ profiles/scanparam/scpp.h profiles/scanparam/scpp.c \
+ profiles/battery/bas.h profiles/battery/bas.c \
+ profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \
src/log.h src/log.c \
attrib/att.h attrib/att.c \
attrib/gatt.h attrib/gatt.c \
diff --git a/Makefile.plugins b/Makefile.plugins
index 38f27ece..5b138129 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -40,7 +40,7 @@ builtin_sources += profiles/sap/main.c profiles/sap/manager.h \
profiles/sap/sap-u8500.c
#noinst_LIBRARIES += profiles/sap/libsap.a
-#profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500
+#profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500.c
endif
endif
@@ -80,7 +80,13 @@ builtin_sources += profiles/input/manager.c \
if TIZEN_UNUSED_PLUGIN
builtin_modules += hog
builtin_sources += profiles/input/hog.c profiles/input/uhid_copy.h \
- profiles/input/suspend.h profiles/input/suspend-dummy.c
+ profiles/input/hog-lib.c profiles/input/hog-lib.h \
+ profiles/deviceinfo/dis.c profiles/deviceinfo/dis.h \
+ profiles/battery/bas.c profiles/battery/bas.h \
+ profiles/scanparam/scpp.c profiles/scanparam/scpp.h \
+ profiles/input/suspend.h profiles/input/suspend-none.c
+
+EXTRA_DIST += profiles/input/suspend-dummy.c
endif
endif
endif
diff --git a/Makefile.tools b/Makefile.tools
index 44f4f57f..115a2409 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -27,21 +27,28 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/l2cap.h monitor/l2cap.c \
monitor/sdp.h monitor/sdp.c \
monitor/avctp.h monitor/avctp.c \
+ monitor/avdtp.h monitor/avdtp.c \
+ monitor/a2dp.h monitor/a2dp.c \
monitor/rfcomm.h monitor/rfcomm.c \
+ monitor/bnep.h monitor/bnep.c \
monitor/uuid.h monitor/uuid.c \
monitor/hwdb.h monitor/hwdb.c \
monitor/keys.h monitor/keys.c \
- monitor/analyze.h monitor/analyze.c
+ monitor/analyze.h monitor/analyze.c \
+ monitor/intel.h monitor/intel.c \
+ monitor/broadcom.h monitor/broadcom.c
monitor_btmon_LDADD = lib/libbluetooth-internal.la \
src/libshared-mainloop.la @UDEV_LIBS@
endif
if EXPERIMENTAL
-noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp tools/3dsp \
+noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp \
+ peripheral/btsensor tools/3dsp \
tools/mgmt-tester tools/gap-tester \
tools/l2cap-tester tools/sco-tester \
tools/smp-tester tools/hci-tester \
- tools/rfcomm-tester
+ tools/rfcomm-tester tools/bnep-tester \
+ tools/userchan-tester
emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
emulator/serial.h emulator/serial.c \
@@ -61,6 +68,15 @@ emulator_b1ee_LDADD = src/libshared-mainloop.la
emulator_hfp_SOURCES = emulator/hfp.c
emulator_hfp_LDADD = src/libshared-mainloop.la
+peripheral_btsensor_SOURCES = peripheral/main.c \
+ peripheral/efivars.h peripheral/efivars.c \
+ peripheral/attach.h peripheral/attach.c \
+ peripheral/log.h peripheral/log.c \
+ peripheral/gap.h peripheral/gap.c \
+ peripheral/gatt.h peripheral/gatt.c
+peripheral_btsensor_LDADD = src/libshared-mainloop.la \
+ lib/libbluetooth-internal.la
+
tools_3dsp_SOURCES = tools/3dsp.c monitor/bt.h
tools_3dsp_LDADD = src/libshared-mainloop.la
@@ -88,6 +104,14 @@ tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c monitor/bt.h \
tools_rfcomm_tester_LDADD = lib/libbluetooth-internal.la \
src/libshared-glib.la @GLIB_LIBS@
+tools_bnep_tester_SOURCES = tools/bnep-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_bnep_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
emulator/hciemu.h emulator/hciemu.c \
emulator/btdev.h emulator/btdev.c \
@@ -116,14 +140,21 @@ tools_sco_tester_LDADD = lib/libbluetooth-internal.la \
tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h
tools_hci_tester_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+tools_userchan_tester_SOURCES = tools/userchan-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_userchan_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
endif
if TOOLS
bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
tools/rfcomm tools/rctest tools/l2test tools/l2ping \
tools/sdptool tools/ciptool tools/bccmd \
- tools/bluemoon tools/hex2hcd tools/mpris-proxy \
- tools/btsnoop
+ tools/bluemoon tools/hex2hcd tools/mpris-proxy
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_st.c \
@@ -135,8 +166,6 @@ tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_sprd.c \
tools/pskey_get.c \
tools/hciattach_bcm43xx.c
-# src/log.c
-# tools/hciattach_bcm43xx.c
tools_hciattach_LDADD = lib/libbluetooth-internal.la
tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
@@ -199,15 +228,6 @@ tools_hex2hcd_SOURCES = tools/hex2hcd.c
tools_mpris_proxy_SOURCES = tools/mpris-proxy.c
tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
-tools_mcaptest_SOURCES = tools/mcaptest.c \
- btio/btio.h btio/btio.c \
- src/log.c src/log.h \
- profiles/health/mcap.h profiles/health/mcap.c
-tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
-
-tools_btsnoop_SOURCES = tools/btsnoop.c
-tools_btsnoop_LDADD = src/libshared-mainloop.la
-
dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
tools/hcitool.1 tools/hcidump.1 \
tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
@@ -232,14 +252,20 @@ EXTRA_DIST += tools/hid2hci.1
endif
if EXPERIMENTAL
+bin_PROGRAMS += tools/btattach
+bin_PROGRAMS += tools/btsnoop
+
noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
tools/scotest tools/amptest tools/hwdb \
tools/hcieventmask tools/hcisecfilter \
- tools/btmgmt tools/btinfo tools/btattach \
+ tools/btinfo \
tools/btproxy \
tools/btiotest tools/bneptest tools/mcaptest \
tools/cltest tools/oobtest tools/seq2bseq \
- tools/ibeacon tools/btgatt-client tools/btgatt-server
+ tools/nokfw tools/create-image \
+ tools/eddystone tools/ibeacon \
+ tools/btgatt-client tools/btgatt-server \
+ tools/test-runner tools/check-selftest
tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
@@ -256,16 +282,15 @@ tools_hwdb_LDADD = lib/libbluetooth-internal.la
tools_hcieventmask_LDADD = lib/libbluetooth-internal.la
-tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c
-tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \
- -lreadline -lncurses
-
tools_btinfo_SOURCES = tools/btinfo.c monitor/bt.h
tools_btinfo_LDADD = src/libshared-mainloop.la
tools_btattach_SOURCES = tools/btattach.c monitor/bt.h
tools_btattach_LDADD = src/libshared-mainloop.la
+tools_btsnoop_SOURCES = tools/btsnoop.c
+tools_btsnoop_LDADD = src/libshared-mainloop.la
+
tools_btproxy_SOURCES = tools/btproxy.c monitor/bt.h
tools_btproxy_LDADD = src/libshared-mainloop.la
@@ -276,7 +301,7 @@ tools_mcaptest_SOURCES = tools/mcaptest.c \
btio/btio.h btio/btio.c \
src/log.c src/log.h \
profiles/health/mcap.h profiles/health/mcap.c
-tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
tools_bneptest_SOURCES = tools/bneptest.c \
btio/btio.h btio/btio.c \
@@ -292,6 +317,13 @@ tools_oobtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
tools_seq2bseq_SOURCES = tools/seq2bseq.c
+tools_nokfw_SOURCES = tools/nokfw.c
+
+tools_create_image_SOURCES = tools/create-image.c
+
+tools_eddystone_SOURCES = tools/eddystone.c monitor/bt.h
+tools_eddystone_LDADD = src/libshared-mainloop.la
+
tools_ibeacon_SOURCES = tools/ibeacon.c monitor/bt.h
tools_ibeacon_LDADD = src/libshared-mainloop.la
@@ -303,11 +335,15 @@ tools_btgatt_server_SOURCES = tools/btgatt-server.c src/uuid-helper.c
tools_btgatt_server_LDADD = src/libshared-mainloop.la \
lib/libbluetooth-internal.la
+dist_man_MANS += tools/btattach.1
+
EXTRA_DIST += tools/bdaddr.1
+else
+EXTRA_DIST += tools/btattach.1
endif
if READLINE
-noinst_PROGRAMS += attrib/gatttool \
+noinst_PROGRAMS += attrib/gatttool tools/btmgmt \
tools/obex-client-tool tools/obex-server-tool \
tools/bluetooth-player tools/obexctl
@@ -337,6 +373,10 @@ tools_obexctl_SOURCES = tools/obexctl.c \
client/display.h client/display.c
tools_obexctl_LDADD = gdbus/libgdbus-internal.la \
@GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c
+tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \
+ -lreadline
endif
if EXPERIMENTAL
@@ -379,4 +419,6 @@ test_scripts += test/sap_client.py test/bluezutils.py \
test/service-ftp.xml test/simple-player test/test-nap \
test/test-heartrate test/test-alert test/test-hfp \
test/test-cyclingspeed test/opp-client test/ftp-client \
- test/pbap-client test/map-client test/advertisement-example
+ test/pbap-client test/map-client test/example-advertisement \
+ test/example-gatt-server test/example-gatt-client \
+ test/test-gatt-profile
diff --git a/TODO b/TODO
index 65e19ee7..8c710efd 100644
--- a/TODO
+++ b/TODO
@@ -61,19 +61,25 @@ General
Priority: Low
Complexity: C2
+- Add queueing support for src/agent.c, currently if there is any request
+ pending the code fail with error EBUSY which is very inconvenient.
+
+ Priority: Low
+ Complexity: C2
+
Low Energy
==========
-- Advertising management. Adapter interface needs to be changed to manage
- connection modes, adapter type and advertising policy. See Volume 3,
- Part C, section 9.3. If Attribute Server is enabled the LE capable
- adapter shall to start advertising. Further investigation is necessary
- to define which connectable mode needs to be supported: Non-connectable,
- directed connectable and undirected connectable. Basically, two connectable
- scenarios shall be addressed:
- 1. GATT client is disconnected, but intends to become a Peripheral to
- receive indications/notifications.
- 2. GATT server intends to accept connections.
+- Connection modes. Adapter interface needs to be changed to manage
+ connection modes and adapter type. See Volume 3, Part C, section 9.3.
+ 1. Mode management: Peripheral / Central
+
+ Priority: Medium
+ Complexity: C2
+
+- Advertising data. The D-Bus interface needs to be updated to enable setting
+ scan response data, and to read the advertising and scan response data which
+ has been broadcast from other LE devices.
Priority: Medium
Complexity: C2
diff --git a/android/Android.mk b/android/Android.mk
index f2188059..38ef4aa9 100644..100755
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -39,10 +39,10 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bluez/android/main.c \
bluez/android/bluetooth.c \
- bluez/android/scpp.c \
- bluez/android/dis.c \
- bluez/android/bas.c \
- bluez/android/hog.c \
+ bluez/profiles/scanparam/scpp.c \
+ bluez/profiles/deviceinfo/dis.c \
+ bluez/profiles/battery/bas.c \
+ bluez/profiles/input/hog-lib.c \
bluez/android/hidhost.c \
bluez/android/socket.c \
bluez/android/ipc.c \
@@ -339,7 +339,10 @@ LOCAL_SRC_FILES := \
bluez/monitor/packet.c \
bluez/monitor/l2cap.c \
bluez/monitor/avctp.c \
+ bluez/monitor/avdtp.c \
+ bluez/monitor/a2dp.c \
bluez/monitor/rfcomm.c \
+ bluez/monitor/bnep.c \
bluez/monitor/uuid.c \
bluez/monitor/sdp.c \
bluez/monitor/vendor.c \
@@ -350,6 +353,8 @@ LOCAL_SRC_FILES := \
bluez/monitor/keys.c \
bluez/monitor/ellisys.c \
bluez/monitor/analyze.c \
+ bluez/monitor/intel.c \
+ bluez/monitor/broadcom.c \
bluez/src/shared/util.c \
bluez/src/shared/queue.c \
bluez/src/shared/crypto.c \
@@ -384,6 +389,7 @@ LOCAL_SRC_FILES := \
bluez/tools/btproxy.c \
bluez/src/shared/mainloop.c \
bluez/src/shared/util.c \
+ bluez/src/shared/ecc.c \
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/bluez \
@@ -539,6 +545,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bluez/tools/btmgmt.c \
bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
bluez/lib/sdp.c \
bluez/src/shared/mainloop.c \
bluez/src/shared/io-mainloop.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index cb32bc3d..154f8db5 100644..100755
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -28,10 +28,13 @@ android_bluetoothd_SOURCES = android/main.c \
src/eir.h src/eir.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
- android/scpp.h android/scpp.c \
- android/dis.h android/dis.c \
- android/bas.h android/bas.c \
- android/hog.h android/hog.c \
+ profiles/scanparam/scpp.h \
+ profiles/scanparam/scpp.c \
+ profiles/deviceinfo/dis.h \
+ profiles/deviceinfo/dis.c \
+ profiles/battery/bas.h profiles/battery/bas.c \
+ profiles/input/hog-lib.h \
+ profiles/input/hog-lib.c \
android/ipc-common.h \
android/ipc.h android/ipc.c \
android/avdtp.h android/avdtp.c \
diff --git a/android/README b/android/README
index 9aa9a377..fa4c42a2 100644..100755
--- a/android/README
+++ b/android/README
@@ -9,7 +9,7 @@ replacement to Android provided Bluetooth stack.
More details about BlueZ for Android architecture and components can be found
in android/hal-ipc-api.txt file.
-Supported Android version: 4.4 KitKat and 5.0 Lollipop
+Supported Android version: 4.4 KitKat and 5.0, 5.1 Lollipop
Building and running on Android
@@ -23,7 +23,7 @@ Build requirements
- GLib - Android 4.2 or later don't provide GLib and one must provide it in
'external/bluetooth/glib' folder of Android tree. Sample Android GLib port
-is available at https://code.google.com/p/aosp-bluez.glib/
+is available at https://github.com/bluez-android/glib
- SBC - A2DP code requires SBC library (version 1.2 or higher) present in
'external/bluetooth/sbc' directory. Library is build from Android.mk provided
@@ -33,7 +33,7 @@ by BlueZ. SBC code is available at git://git.kernel.org/pub/scm/bluetooth/sbc
BlueZ on Android 4.4 requires backporting missing features (epoll_create1 and
ppoll calls). Sample Bionic for Android 4.4 with all required features
backported is available at
-https://code.google.com/p/aosp-bluez.platform-bionic/
+https://github.com/bluez-android/aosp_platform_bionic
Runtime requirements
--------------------
@@ -46,9 +46,9 @@ board:
import init.bluetooth.rc
For convenience examples are provided at:
-https://code.google.com/p/aosp-bluez.device-lge-mako/ (Nexus 4)
-https://code.google.com/p/aosp-bluez.device-lge-ham/ (Nexus 5)
-https://code.google.com/p/aosp-bluez.device-asus-flo/ (Nexus 7 2013)
+https://github.com/bluez-android/aosp_device_lge_mako (Nexus 4)
+https://github.com/bluez-android/aosp_device_lge_hammerhead (Nexus 5)
+https://github.com/bluez-android/aosp_device_asus_flo (Nexus 7 2013)
Security-Enhanced Linux in Android
----------------------------------
@@ -62,14 +62,14 @@ bluetoothd.te
bluetoothd_snoop.te
For convenience sepolicy.git with all required policies is available at:
-https://code.google.com/p/aosp-bluez.external-sepolicy/
+https://github.com/bluez-android/aosp_platform_external_sepolicy
Downloading and building
------------------------
Building for Android requires full Android AOSP source tree. Sample Android tree
with all required components present is available at
-http://code.google.com/p/aosp-bluez/
+https://github.com/bluez-android
This tree provides support for Nexus4 (mako), Nexus 5 (hammerhead) and
Nexus 7 2013 (flo, deb). Tree does not provide binary blobs needed to run
@@ -81,7 +81,8 @@ Downloading:
Android 5.0 - 'lollipop' branch
Android 4.4 - 'kitkat' branch
-repo init -u https://code.google.com/p/aosp-bluez.platform-manifest -b lollipop
+repo init -u https://github.com/bluez-android/aosp_platform_manifest \
+ -b lollipop
repo sync
Building:
@@ -152,8 +153,7 @@ CONFIG_BT_HCIBTUSB
If it is not possible to use new enough Linux kernel one can use updated
bluetooth subsystem from Backports project. More information about Backports can
be found at https://backports.wiki.kernel.org. Sample kernels using backports
-for running BlueZ on Android are available at
-https://code.google.com/p/aosp-bluez.
+for running BlueZ on Android are available at https://github.com/bluez-android.
Running with Valgrind
@@ -176,7 +176,7 @@ It's recommended to have unstripped libglib.so installed which will enable
complete backtraces in Valgrind output. Otherwise, in many cases backtrace
will break at e.g. g_free() function without prior callers. It's possible to
have proper library installed automatically by appropriate entry in Android.mk,
-see https://code.google.com/p/aosp-bluez.glib/ for an example.
+see https://github.com/bluez-android/glib for an example.
When running with valgrind SElinux needs to be set into permissive mode. This
can be done by executing 'setenforce 0' from root shell.
@@ -207,7 +207,7 @@ It is possible to customize BlueZ for Android through Android system properties.
This may include enabling extra profiles or features inside HALs implementation
These properties are read on Bluetooth stack startup only and require stack
restart if changed. All customization properties names start with
-"persist.sys.bluetooth." or "ro.bluerooth." followed by specific HAL name e.g.
+"persist.sys.bluetooth." or "ro.bluetooth." followed by specific HAL name e.g.
"persist.sys.bluetooth.handsfree". If both are present "persist.sys.bluetooth."
takes precedence. This allows for read only properties to be set during build
leaving enough flexibility for developing or debugging purposes.
@@ -402,12 +402,16 @@ affect qualification or user experience. This section provides list of
recommended Android fixes that are not part of latest AOSP release supported by
BlueZ.
+For Android 5.1 Lollipop:
+https://android-review.googlesource.com/177314
+
For Android 5.0 Lollipop:
https://android-review.googlesource.com/99761
https://android-review.googlesource.com/100297
https://android-review.googlesource.com/102882
https://android-review.googlesource.com/132733
https://android-review.googlesource.com/132763
+https://android-review.googlesource.com/177314
For Android 4.4 KitKat:
https://android-review.googlesource.com/82757
@@ -417,6 +421,7 @@ https://android-review.googlesource.com/99761
https://android-review.googlesource.com/99850
https://android-review.googlesource.com/100297
https://android-review.googlesource.com/102882
+https://android-review.googlesource.com/177314
Unimplemented Bluetooth features
================================
diff --git a/android/a2dp-sink.c b/android/a2dp-sink.c
index 7c1e1a03..7c1e1a03 100644..100755
--- a/android/a2dp-sink.c
+++ b/android/a2dp-sink.c
diff --git a/android/a2dp-sink.h b/android/a2dp-sink.h
index d2c5ff42..d2c5ff42 100644..100755
--- a/android/a2dp-sink.h
+++ b/android/a2dp-sink.h
diff --git a/android/a2dp.c b/android/a2dp.c
index f2190420..f2190420 100644..100755
--- a/android/a2dp.c
+++ b/android/a2dp.c
diff --git a/android/a2dp.h b/android/a2dp.h
index 8a704073..8a704073 100644..100755
--- a/android/a2dp.h
+++ b/android/a2dp.h
diff --git a/android/audio-ipc-api.txt b/android/audio-ipc-api.txt
index f4a497dd..f4a497dd 100644..100755
--- a/android/audio-ipc-api.txt
+++ b/android/audio-ipc-api.txt
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 7b9553ba..7b9553ba 100644..100755
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
diff --git a/android/avctp.c b/android/avctp.c
index 6aa64cf0..6aa64cf0 100644..100755
--- a/android/avctp.c
+++ b/android/avctp.c
diff --git a/android/avctp.h b/android/avctp.h
index f0da2b33..f0da2b33 100644..100755
--- a/android/avctp.h
+++ b/android/avctp.h
diff --git a/android/avdtp.c b/android/avdtp.c
index 7e61280c..bab305be 100644..100755
--- a/android/avdtp.c
+++ b/android/avdtp.c
@@ -1567,7 +1567,7 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
for (i = 0; i < seid_count; i++, seid++) {
failed_seid = seid->seid;
- sep = find_local_sep_by_seid(session, req->first_seid.seid);
+ sep = find_local_sep_by_seid(session, seid->seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1678,7 +1678,7 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
for (i = 0; i < seid_count; i++, seid++) {
failed_seid = seid->seid;
- sep = find_local_sep_by_seid(session, req->first_seid.seid);
+ sep = find_local_sep_by_seid(session, seid->seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -3398,10 +3398,7 @@ struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
sep->info.type, sep->codec, sep->info.seid);
- if (!queue_push_tail(lseps, sep)) {
- g_free(sep);
- return NULL;
- }
+ queue_push_tail(lseps, sep);
return sep;
}
diff --git a/android/avdtp.h b/android/avdtp.h
index 07516a87..07516a87 100644..100755
--- a/android/avdtp.h
+++ b/android/avdtp.h
diff --git a/android/avdtptest.c b/android/avdtptest.c
index f42f6648..ce344437 100644..100755
--- a/android/avdtptest.c
+++ b/android/avdtptest.c
@@ -826,13 +826,13 @@ int main(int argc, char *argv[])
dev_role = AVDTP_SEP_TYPE_SINK;
} else {
usage();
- exit(0);
+ exit(1);
}
break;
case 'c':
if (str2ba(optarg, &dst) < 0) {
usage();
- exit(0);
+ exit(1);
}
break;
case 'l':
@@ -855,22 +855,26 @@ int main(int argc, char *argv[])
if (version != 0x0100 && version != 0x0102 &&
version != 0x0103) {
printf("invalid version\n");
- exit(0);
+ exit(1);
}
break;
case 'h':
- default:
usage();
exit(0);
+ default:
+ usage();
+ exit(1);
}
}
+ lseps = queue_new();
+
local_sep = avdtp_register_sep(lseps, dev_role, AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, &sep_cfm, NULL);
if (!local_sep) {
printf("Failed to register sep\n");
- exit(0);
+ exit(1);
}
queue_push_tail(lseps, local_sep);
@@ -886,7 +890,7 @@ int main(int argc, char *argv[])
if (!io) {
printf("Failed: %s\n", err->message);
g_error_free(err);
- exit(0);
+ exit(1);
}
g_main_loop_run(mainloop);
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 4edfd0e9..4edfd0e9 100644..100755
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index add7739c..6554b122 100644..100755
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -224,7 +224,7 @@ struct avrcp_control_cfm {
char **text, void *user_data);
bool (*register_notification) (struct avrcp *session, int err,
uint8_t code, uint8_t event,
- uint8_t *params, void *user_data);
+ void *params, void *user_data);
void (*set_volume) (struct avrcp *session, int err, uint8_t volume,
void *user_data);
void (*set_addressed) (struct avrcp *session, int err,
diff --git a/android/avrcp.c b/android/avrcp.c
index bcb42284..8c3e25a9 100644..100755
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -748,11 +748,12 @@ static const struct avrcp_control_ind control_ind = {
static bool handle_register_notification_rsp(struct avrcp *session, int err,
uint8_t code, uint8_t event,
- uint8_t *params,
+ void *params,
void *user_data)
{
struct avrcp_device *dev = user_data;
struct hal_ev_avrcp_volume_changed ev;
+ uint8_t *volume = params;
if (err < 0) {
error("AVRCP: %s", strerror(-err));
@@ -766,7 +767,7 @@ static bool handle_register_notification_rsp(struct avrcp *session, int err,
return false;
ev.type = code;
- ev.volume = params[0] & 0x7f;
+ ev.volume = volume[0];
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
HAL_EV_AVRCP_VOLUME_CHANGED,
diff --git a/android/avrcp.h b/android/avrcp.h
index 11e79b7d..11e79b7d 100644..100755
--- a/android/avrcp.h
+++ b/android/avrcp.h
diff --git a/android/bas.c b/android/bas.c
index dcbf9de7..dcbf9de7 100644..100755
--- a/android/bas.c
+++ b/android/bas.c
diff --git a/android/bas.h b/android/bas.h
index 3e175b5b..3e175b5b 100644..100755
--- a/android/bas.h
+++ b/android/bas.h
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 4d0cd48e..51a31fec 100644..100755
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -3961,9 +3961,6 @@ bool bt_le_set_advertising(bool advertising, bt_le_set_advertising_done cb,
uint8_t adv = advertising ? 0x01 : 0x00;
data = new0(struct adv_user_data, 1);
- if (!data)
- return false;
-
data->cb = cb;
data->user_data = user_data;
@@ -4078,9 +4075,6 @@ bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
cp.addr.type = dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
data = new0(struct read_rssi_user_data, 1);
- if (!data)
- return false;
-
data->cb = cb;
data->user_data = user_data;
@@ -5249,18 +5243,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)
DBG("mode 0x%x", mode);
unpaired_cb_list = queue_new();
- if (!unpaired_cb_list) {
- error("Cannot allocate queue for unpaired callbacks");
- return false;
- }
-
paired_cb_list = queue_new();
- if (!paired_cb_list) {
- error("Cannot allocate queue for paired callbacks");
- queue_destroy(unpaired_cb_list, NULL);
- unpaired_cb_list = NULL;
- return false;
- }
missing_settings = adapter.current_settings ^
adapter.supported_settings;
diff --git a/android/bluetooth.h b/android/bluetooth.h
index 4b172093..4b172093 100644..100755
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
diff --git a/android/bluetoothd-snoop.c b/android/bluetoothd-snoop.c
index ff2b7e51..7526782f 100644..100755
--- a/android/bluetoothd-snoop.c
+++ b/android/bluetoothd-snoop.c
@@ -73,6 +73,9 @@ static uint32_t get_flags_from_opcode(uint16_t opcode)
case BTSNOOP_OPCODE_SCO_TX_PKT:
case BTSNOOP_OPCODE_SCO_RX_PKT:
break;
+ case BTSNOOP_OPCODE_OPEN_INDEX:
+ case BTSNOOP_OPCODE_CLOSE_INDEX:
+ break;
}
return 0xff;
@@ -145,11 +148,7 @@ static int open_monitor(const char *path)
struct sockaddr_hci addr;
int opt = 1;
-#ifdef __TIZEN_PATCH__
- snoop = btsnoop_create(path, BTSNOOP_TYPE_HCI, -1, -1);
-#else
- snoop = btsnoop_create(path, BTSNOOP_TYPE_HCI);
-#endif
+ snoop = btsnoop_create(path, BTSNOOP_FORMAT_HCI);
if (!snoop)
return -1;
diff --git a/android/bluetoothd-wrapper.c b/android/bluetoothd-wrapper.c
index 7f668dac..7f668dac 100644..100755
--- a/android/bluetoothd-wrapper.c
+++ b/android/bluetoothd-wrapper.c
diff --git a/android/bluetoothd.te b/android/bluetoothd.te
index 532bfbb3..532bfbb3 100644..100755
--- a/android/bluetoothd.te
+++ b/android/bluetoothd.te
diff --git a/android/bluetoothd_snoop.te b/android/bluetoothd_snoop.te
index ef817b5b..ef817b5b 100644..100755
--- a/android/bluetoothd_snoop.te
+++ b/android/bluetoothd_snoop.te
diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index 4723024e..c9acf6c8 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -118,10 +118,19 @@ void add_remote_device(const bt_bdaddr_t *addr)
/* Realloc space if needed */
if (remote_devices_cnt >= remote_devices_capacity) {
+ bt_bdaddr_t *tmp;
+
remote_devices_capacity *= 2;
+ /*
+ * Save reference to previously allocated memory block so that
+ * it can be freed in case realloc fails.
+ */
+ tmp = remote_devices;
+
remote_devices = realloc(remote_devices, sizeof(bt_bdaddr_t) *
remote_devices_capacity);
if (remote_devices == NULL) {
+ free(tmp);
remote_devices_capacity = 0;
remote_devices_cnt = 0;
return;
diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 70287fc3..35267832 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -679,7 +679,7 @@ static void gattc_listen_cb(int status, int client_if)
/* Callback invoked when the MTU for a given connection changes */
static void gattc_configure_mtu_cb(int conn_id, int status, int mtu)
{
- haltest_info("%s: conn_id=%d, status=%d, mtu=%d", __func__, conn_id,
+ haltest_info("%s: conn_id=%d, status=%d, mtu=%d\n", __func__, conn_id,
status, mtu);
}
@@ -1170,13 +1170,13 @@ static void scan_p(int argc, const char **argv)
/* start */
if (argc >= 4)
- start = atoi(argv[3]);
+ start = strtol(argv[3], NULL, 0);
EXEC(if_gatt->client->scan, client_if, start);
#else
/* start */
if (argc >= 3)
- start = atoi(argv[2]);
+ start = strtol(argv[2], NULL, 0);
EXEC(if_gatt->client->scan, start);
#endif
@@ -1211,14 +1211,14 @@ static void connect_p(int argc, const char **argv)
/* is_direct */
if (argc > 4)
- is_direct = atoi(argv[4]);
+ is_direct = strtol(argv[4], NULL, 0);
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
EXEC(if_gatt->client->connect, client_if, &bd_addr, is_direct);
#else
/* transport */
if (argc > 5)
- transport = atoi(argv[5]);
+ transport = strtol(argv[5], NULL, 0);
EXEC(if_gatt->client->connect, client_if, &bd_addr, is_direct,
transport);
@@ -1272,7 +1272,7 @@ static void listen_p(int argc, const char **argv)
/* start */
if (argc >= 4)
- start = atoi(argv[3]);
+ start = strtol(argv[3], NULL, 0);
EXEC(if_gatt->client->listen, client_if, start);
}
@@ -1412,7 +1412,7 @@ static void read_characteristic_p(int argc, const char **argv)
/* auth_req */
if (argc > 5)
- auth_req = atoi(argv[5]);
+ auth_req = strtol(argv[5], NULL, 0);
EXEC(if_gatt->client->read_characteristic, conn_id, &srvc_id, &char_id,
auth_req);
@@ -1458,13 +1458,13 @@ static void write_characteristic_p(int argc, const char **argv)
haltest_error("No write type specified\n");
return;
}
- write_type = atoi(argv[5]);
+ write_type = strtol(argv[5], NULL, 0);
GET_VERIFY_HEX_STRING(6, value, len);
/* auth_req */
if (argc > 7)
- auth_req = atoi(argv[7]);
+ auth_req = strtol(argv[7], NULL, 0);
EXEC(if_gatt->client->write_characteristic, conn_id, &srvc_id, &char_id,
write_type, len, auth_req, (char *) value);
@@ -1491,7 +1491,7 @@ static void read_descriptor_p(int argc, const char **argv)
/* auth_req */
if (argc > 6)
- auth_req = atoi(argv[6]);
+ auth_req = strtol(argv[6], NULL, 0);
EXEC(if_gatt->client->read_descriptor, conn_id, &srvc_id, &char_id,
&descr_id, auth_req);
@@ -1539,7 +1539,7 @@ static void write_descriptor_p(int argc, const char **argv)
haltest_error("No write type specified\n");
return;
}
- write_type = atoi(argv[6]);
+ write_type = strtol(argv[6], NULL, 0);
/* value */
if (argc <= 7) {
@@ -1557,7 +1557,7 @@ static void write_descriptor_p(int argc, const char **argv)
/* auth_req */
if (argc > 8)
- auth_req = atoi(argv[8]);
+ auth_req = strtol(argv[8], NULL, 0);
EXEC(if_gatt->client->write_descriptor, conn_id, &srvc_id, &char_id,
&descr_id, write_type, len, auth_req, (char *) value);
@@ -1581,7 +1581,7 @@ static void execute_write_p(int argc, const char **argv)
haltest_error("No execute specified\n");
return;
}
- execute = atoi(argv[3]);
+ execute = strtol(argv[3], NULL, 0);
EXEC(if_gatt->client->execute_write, conn_id, execute);
}
@@ -1807,7 +1807,7 @@ static void scan_filter_enable_p(int argc, const char **argv)
/* enable */
if (argc >= 4)
- enable = atoi(argv[3]);
+ enable = strtol(argv[3], NULL, 0);
EXEC(if_gatt->client->scan_filter_clear, client_if, enable);
}
@@ -1841,13 +1841,13 @@ static void set_adv_data_p(int argc, const char **argv)
/* set scan response */
if (argc >= 4)
- set_scan_rsp = atoi(argv[3]);
+ set_scan_rsp = strtol(argv[3], NULL, 0);
/* include name */
if (argc >= 5)
- include_name = atoi(argv[4]);
+ include_name = strtol(argv[4], NULL, 0);
/* include txpower */
if (argc >= 6)
- include_txpower = atoi(argv[5]);
+ include_txpower = strtol(argv[5], NULL, 0);
VERIFY_MIN_INTERVAL(6, min_interval);
VERIFY_MAX_INTERVAL(7, max_interval);
@@ -2018,13 +2018,13 @@ static void multi_adv_set_inst_data_p(int argc, const char **argv)
/* set scan response */
if (argc >= 4)
- set_scan_rsp = atoi(argv[3]);
+ set_scan_rsp = strtol(argv[3], NULL, 0);
/* include name */
if (argc >= 5)
- include_name = atoi(argv[4]);
+ include_name = strtol(argv[4], NULL, 0);
/* include txpower */
if (argc >= 6)
- include_txpower = atoi(argv[5]);
+ include_txpower = strtol(argv[5], NULL, 0);
VERIFY_APPEARANCE(6, appearance);
GET_VERIFY_HEX_STRING(7, manufacturer_data, manufacturer_len);
@@ -2206,7 +2206,7 @@ static void test_command_p(int argc, const char **argv)
haltest_error("No command specified\n");
return;
}
- command = atoi(argv[2]);
+ command = strtol(argv[2], NULL, 0);
VERIFY_ADDR_ARG(3, &bd_addr);
VERIFY_UUID(4, &uuid);
@@ -2366,14 +2366,14 @@ static void gatts_connect_p(int argc, const char *argv[])
/* is_direct */
if (argc > 4)
- is_direct = atoi(argv[4]);
+ is_direct = strtol(argv[4], NULL, 0);
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct);
#else
/* transport */
if (argc > 5)
- transport = atoi(argv[5]);
+ transport = strtol(argv[5], NULL, 0);
EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct,
transport);
@@ -2431,7 +2431,7 @@ static void gatts_add_service_p(int argc, const char *argv[])
haltest_error("No num_handles specified\n");
return;
}
- num_handles = atoi(argv[4]);
+ num_handles = strtol(argv[4], NULL, 0);
EXEC(if_gatt->server->add_service, server_if, &srvc_id, num_handles);
}
@@ -2479,14 +2479,14 @@ static void gatts_add_characteristic_p(int argc, const char *argv[])
haltest_error("No properties specified\n");
return;
}
- properties = atoi(argv[5]);
+ properties = strtol(argv[5], NULL, 0);
/* permissions */
if (argc <= 6) {
haltest_error("No permissions specified\n");
return;
}
- permissions = atoi(argv[6]);
+ permissions = strtol(argv[6], NULL, 0);
EXEC(if_gatt->server->add_characteristic, server_if, service_handle,
&uuid, properties, permissions);
@@ -2514,7 +2514,7 @@ static void gatts_add_descriptor_p(int argc, const char *argv[])
haltest_error("No permissions specified\n");
return;
}
- permissions = atoi(argv[5]);
+ permissions = strtol(argv[5], NULL, 0);
EXEC(if_gatt->server->add_descriptor, server_if, service_handle, &uuid,
permissions);
@@ -2540,7 +2540,7 @@ static void gatts_start_service_p(int argc, const char *argv[])
haltest_error("No transport specified\n");
return;
}
- transport = atoi(argv[4]);
+ transport = strtol(argv[4], NULL, 0);
EXEC(if_gatt->server->start_service, server_if, service_handle,
transport);
@@ -2601,7 +2601,7 @@ static void gatts_send_indication_p(int argc, const char *argv[])
haltest_error("No transport specified\n");
return;
}
- confirm = atoi(argv[5]);
+ confirm = strtol(argv[5], NULL, 0);
GET_VERIFY_HEX_STRING(6, data, len);
diff --git a/android/client/if-hl.c b/android/client/if-hl.c
index e0818ba1..bd056711 100644
--- a/android/client/if-hl.c
+++ b/android/client/if-hl.c
@@ -201,6 +201,10 @@ static void register_application_p(int argc, const char **argv)
reg.number_of_mdeps = atoi(argv[6]);
reg.mdep_cfg = malloc(reg.number_of_mdeps * sizeof(bthl_mdep_cfg_t));
+ if (!reg.mdep_cfg) {
+ haltest_error("malloc failed\n");
+ return;
+ }
mdep_argc_init = 7;
for (i = 0; i < reg.number_of_mdeps; i++) {
diff --git a/android/cts.txt b/android/cts.txt
index f6792634..f6792634 100644..100755
--- a/android/cts.txt
+++ b/android/cts.txt
diff --git a/android/dis.c b/android/dis.c
index 75dbe3d3..75dbe3d3 100644..100755
--- a/android/dis.c
+++ b/android/dis.c
diff --git a/android/dis.h b/android/dis.h
index faf27b3d..faf27b3d 100644..100755
--- a/android/dis.h
+++ b/android/dis.h
diff --git a/android/gatt.c b/android/gatt.c
index 4da959fe..28635edf 100644..100755
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -744,37 +744,14 @@ static struct gatt_device *create_device(const bdaddr_t *addr)
struct gatt_device *dev;
dev = new0(struct gatt_device, 1);
- if (!dev)
- return NULL;
bacpy(&dev->bdaddr, addr);
dev->services = queue_new();
- if (!dev->services) {
- error("gatt: Failed to allocate memory for client");
- destroy_device(dev);
- return NULL;
- }
-
dev->autoconnect_apps = queue_new();
- if (!dev->autoconnect_apps) {
- error("gatt: Failed to allocate memory for client");
- destroy_device(dev);
- return NULL;
- }
-
dev->pending_requests = queue_new();
- if (!dev->pending_requests) {
- error("gatt: Failed to allocate memory for client");
- destroy_device(dev);
- return NULL;
- }
- if (!queue_push_head(gatt_devices, dev)) {
- error("gatt: Cannot push device to queue");
- destroy_device(dev);
- return NULL;
- }
+ queue_push_head(gatt_devices, dev);
return device_ref(dev);
}
@@ -978,6 +955,11 @@ static void notify_mtu_change(void *data, void *user_data)
if (conn->device != device)
return;
+ if (!conn->app) {
+ error("gatt: can't notify mtu - no app registered for conn");
+ return;
+ }
+
switch (conn->app->type) {
case GATT_CLIENT:
notify_client_mtu_change(conn, true);
@@ -1111,25 +1093,13 @@ static struct app_connection *create_connection(struct gatt_device *device,
/* Check if already connected */
new_conn = new0(struct app_connection, 1);
- if (!new_conn)
- return NULL;
/* Make connection id unique to connection record (app, device) pair */
new_conn->app = app;
new_conn->id = last_conn_id++;
-
new_conn->transactions = queue_new();
- if (!new_conn->transactions) {
- free(new_conn);
- return NULL;
- }
- if (!queue_push_head(app_connections, new_conn)) {
- error("gatt: Cannot push client on the client queue!?");
- queue_destroy(new_conn->transactions, free);
- free(new_conn);
- return NULL;
- }
+ queue_push_head(app_connections, new_conn);
new_conn->device = device_ref(device);
@@ -1142,33 +1112,15 @@ static struct service *create_service(uint8_t id, bool primary, char *uuid,
struct service *s;
s = new0(struct service, 1);
- if (!s) {
- error("gatt: Cannot allocate memory for gatt_primary");
- return NULL;
- }
-
- s->chars = queue_new();
- if (!s->chars) {
- error("gatt: Cannot allocate memory for char cache");
- free(s);
- return NULL;
- }
-
- s->included = queue_new();
- if (!s->included) {
- error("gatt: Cannot allocate memory for included queue");
- queue_destroy(s->chars, NULL);
- free(s);
- return NULL;
- }
if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
error("gatt: Cannot convert string to uuid");
- queue_destroy(s->chars, NULL);
free(s);
return NULL;
}
+ s->chars = queue_new();
+ s->included = queue_new();
s->id.instance = id;
/* Put primary service to our local list */
@@ -1251,12 +1203,7 @@ static void discover_srvc_by_uuid_cb(uint8_t status, GSList *ranges,
goto reply;
}
- if (!queue_push_tail(dev->services, s)) {
- error("gatt: Cannot push primary service to the list");
- destroy_service(s);
- gatt_status = GATT_FAILURE;
- goto reply;
- }
+ queue_push_tail(dev->services, s);
send_client_primary_notify(s, INT_TO_PTR(cb_data->conn->id));
@@ -1313,11 +1260,7 @@ static void discover_srvc_all_cb(uint8_t status, GSList *services,
if (!p)
continue;
- if (!queue_push_tail(dev->services, p)) {
- error("gatt: Cannot push primary service to the list");
- free(p);
- continue;
- }
+ queue_push_tail(dev->services, p);
DBG("attr handle = 0x%04x, end grp handle = 0x%04x uuid: %s",
prim->range.start, prim->range.end, prim->uuid);
@@ -1407,11 +1350,6 @@ static guint search_dev_for_srvc(struct app_connection *conn, bt_uuid_t *uuid)
struct discover_srvc_data *cb_data;
cb_data = new0(struct discover_srvc_data, 1);
- if (!cb_data) {
- error("gatt: Cannot allocate cb data");
- return 0;
- }
-
cb_data->conn = conn;
if (uuid) {
@@ -1564,7 +1502,7 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
if (cid == ATT_CID)
mtu = ATT_DEFAULT_LE_MTU;
- attrib = g_attrib_new(io, mtu);
+ attrib = g_attrib_new(io, mtu, true);
if (!attrib) {
error("gatt: unable to create new GAttrib instance");
device_set_state(dev, DEVICE_DISCONNECTED);
@@ -1642,7 +1580,6 @@ reply:
/*
* There is no ongoing bonding, lets search for primary
* services
- *
*/
search_dev_for_srvc(conn, NULL);
}
@@ -1653,7 +1590,7 @@ reply:
&data);
/* For BR/EDR notify about MTU since it is not negotiable*/
- if (cid != ATT_CID)
+ if (cid != ATT_CID && status == GATT_SUCCESS)
queue_foreach(app_connections, notify_mtu_change, dev);
device_unref(dev);
@@ -1775,7 +1712,7 @@ done:
dev = create_device(addr);
}
- if (!dev || dev->state != DEVICE_CONNECT_INIT)
+ if (dev->state != DEVICE_CONNECT_INIT)
return;
device_set_state(dev, DEVICE_CONNECT_READY);
@@ -1798,38 +1735,20 @@ static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
}
app = new0(struct gatt_app, 1);
- if (!app) {
- error("gatt: Cannot allocate memory for registering app");
- return NULL;
- }
app->type = type;
- if (app->type == GATT_CLIENT) {
+ if (app->type == GATT_CLIENT)
app->notifications = queue_new();
- if (!app->notifications) {
- error("gatt: couldn't allocate notifications queue");
- destroy_gatt_app(app);
- return NULL;
- }
- }
memcpy(app->uuid, uuid, sizeof(app->uuid));
app->id = application_id++;
- if (!queue_push_head(gatt_apps, app)) {
- error("gatt: Cannot push app on the list");
- destroy_gatt_app(app);
- return NULL;
- }
+ queue_push_head(gatt_apps, app);
- if ((app->type == GATT_SERVER) &&
- !queue_push_tail(listen_apps, INT_TO_PTR(app->id))) {
- error("gatt: Cannot push server on the list");
- destroy_gatt_app(app);
- return NULL;
- }
+ if (app->type == GATT_SERVER)
+ queue_push_tail(listen_apps, INT_TO_PTR(app->id));
return app;
}
@@ -1972,6 +1891,7 @@ static bool trigger_connection(struct app_connection *conn, bool direct)
if (direct)
return connect_le(conn->device) == 0;
+ bt_gatt_add_autoconnect(conn->app->id, &conn->device->bdaddr);
return auto_connect_le(conn->device);
case DEVICE_CONNECTED:
notify_app_connect_status(conn, GATT_SUCCESS);
@@ -2051,9 +1971,6 @@ static struct listen_data *create_listen_data(int32_t client_id, bool start)
struct listen_data *d;
d = new0(struct listen_data, 1);
- if (!d)
- return NULL;
-
d->client_id = client_id;
d->start = start;
@@ -2103,11 +2020,6 @@ static void handle_client_unregister(const void *buf, uint16_t len)
if (!advertising_cnt) {
data = create_listen_data(cmd->client_if, false);
- if (!data) {
- error("gatt: Could not allocate listen data");
- status = HAL_STATUS_NOMEM;
- goto reply;
- }
if (!bt_le_set_advertising(data->start, set_advertising_cb,
data)) {
@@ -2139,11 +2051,8 @@ static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr, bool direct)
return HAL_STATUS_FAILED;
device = find_device_by_addr(addr);
- if (!device) {
+ if (!device)
device = create_device(addr);
- if (!device)
- return HAL_STATUS_FAILED;
- }
conn_match.device = device;
conn_match.app = app;
@@ -2224,12 +2133,7 @@ static void handle_client_listen(const void *buf, uint16_t len)
goto reply;
}
- if (!queue_push_tail(listen_apps,
- INT_TO_PTR(cmd->client_if))) {
- error("gatt: Could not put client on listen queue");
- status = HAL_STATUS_FAILED;
- goto reply;
- }
+ queue_push_tail(listen_apps, INT_TO_PTR(cmd->client_if));
/* If listen is already on just return success*/
if (advertising_cnt > 0) {
@@ -2259,11 +2163,6 @@ static void handle_client_listen(const void *buf, uint16_t len)
}
data = create_listen_data(cmd->client_if, cmd->start);
- if (!data) {
- error("gatt: Could not allocate listen data");
- status = HAL_STATUS_NOMEM;
- goto reply;
- }
if (!bt_le_set_advertising(cmd->start, set_advertising_cb, data)) {
error("gatt: Could not set advertising");
@@ -2502,12 +2401,8 @@ static void get_included_cb(uint8_t status, GSList *included, void *user_data)
* 1. on services queue together with primary service
* 2. on special queue inside primary service
*/
- if (!queue_push_tail(service->included, incl) ||
- !queue_push_tail(conn->device->services, incl)) {
- error("gatt: Cannot push incl service to the list");
- destroy_service(incl);
- continue;
- }
+ queue_push_tail(service->included, incl);
+ queue_push_tail(conn->device->services, incl);
}
/*
@@ -2520,18 +2415,13 @@ failed:
send_client_incl_service_notify(&service->id, incl, conn->id);
}
-static bool search_included_services(struct app_connection *conn,
+static void search_included_services(struct app_connection *conn,
struct service *service)
{
struct get_included_data *data;
uint16_t start, end;
data = new0(struct get_included_data, 1);
- if (!data) {
- error("gatt: failed to allocate memory for included_data");
- return false;
- }
-
data->prim = service;
data->conn = conn;
@@ -2545,8 +2435,6 @@ static bool search_included_services(struct app_connection *conn,
gatt_find_included(conn->device->attrib, start, end, get_included_cb,
data);
-
- return true;
}
static bool find_service(int32_t conn_id, struct element_id *service_id,
@@ -2605,13 +2493,9 @@ static void handle_client_get_included_service(const void *buf, uint16_t len)
}
if (!prim_service->incl_search_done) {
- if (search_included_services(conn, prim_service)) {
- status = HAL_STATUS_SUCCESS;
- goto reply;
- }
-
- status = HAL_STATUS_FAILED;
- goto notify;
+ search_included_services(conn, prim_service);
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
}
/* Try to use cache here */
@@ -2691,17 +2575,7 @@ static void cache_all_srvc_chars(struct service *srvc, GSList *characteristics)
struct characteristic *ch;
ch = new0(struct characteristic, 1);
- if (!ch) {
- error("gatt: Error while caching characteristic");
- continue;
- }
-
ch->descriptors = queue_new();
- if (!ch->descriptors) {
- error("gatt: Error while caching characteristic");
- free(ch);
- continue;
- }
memcpy(&ch->ch, characteristics->data, sizeof(ch->ch));
@@ -2727,10 +2601,7 @@ static void cache_all_srvc_chars(struct service *srvc, GSList *characteristics)
DBG("attr handle = 0x%04x, end handle = 0x%04x uuid: %s",
ch->ch.handle, ch->end_handle, ch->ch.uuid);
- if (!queue_push_tail(srvc->chars, ch)) {
- error("gatt: Error while caching characteristic");
- destroy_characteristic(ch);
- }
+ queue_push_tail(srvc->chars, ch);
}
}
@@ -2792,12 +2663,6 @@ static void handle_client_get_characteristic(const void *buf, uint16_t len)
struct att_range range;
cb_data = new0(struct discover_char_data, 1);
- if (!cb_data) {
- error("gatt: Cannot allocate cb data");
- status = HAL_STATUS_FAILED;
- goto done;
- }
-
cb_data->service = srvc;
cb_data->conn_id = conn->id;
@@ -2884,8 +2749,6 @@ static void gatt_discover_desc_cb(guint8 status, GSList *descs,
bt_uuid_t uuid;
descr = new0(struct descriptor, 1);
- if (!descr)
- continue;
bt_string_to_uuid(&uuid, desc->uuid);
bt_uuid_to_uuid128(&uuid, &descr->id.uuid);
@@ -2895,8 +2758,7 @@ static void gatt_discover_desc_cb(guint8 status, GSList *descs,
DBG("attr handle = 0x%04x, uuid: %s", desc->handle, desc->uuid);
- if (!queue_push_tail(ch->descriptors, descr))
- free(descr);
+ queue_push_tail(ch->descriptors, descr);
}
reply:
@@ -2924,9 +2786,6 @@ static bool build_descr_cache(struct app_connection *conn, struct service *srvc,
return false;
cb_data = new0(struct discover_desc_data, 1);
- if (!cb_data)
- return false;
-
cb_data->conn = conn;
cb_data->srvc = srvc;
cb_data->ch = ch;
@@ -3028,9 +2887,6 @@ static struct char_op_data *create_char_op_data(int32_t conn_id,
struct char_op_data *d;
d = new0(struct char_op_data, 1);
- if (!d)
- return NULL;
-
d->conn_id = conn_id;
d->srvc_id = s_id;
d->char_id = ch_id;
@@ -3211,11 +3067,6 @@ static void handle_client_read_characteristic(const void *buf, uint16_t len)
cb_data = create_char_op_data(cmd->conn_id, &srvc->id, &ch->id,
cmd->srvc_id.is_primary);
- if (!cb_data) {
- error("gatt: Cannot allocate cb data");
- status = HAL_STATUS_NOMEM;
- goto failed;
- }
if (!set_auth_type(conn->device, cmd->auth_req)) {
error("gatt: Failed to set security %d", cmd->auth_req);
@@ -3349,11 +3200,6 @@ static void handle_client_write_characteristic(const void *buf, uint16_t len)
cmd->write_type == GATT_WRITE_TYPE_DEFAULT) {
cb_data = create_char_op_data(cmd->conn_id, &srvc->id, &ch->id,
cmd->srvc_id.is_primary);
- if (!cb_data) {
- error("gatt: Cannot allocate call data");
- status = HAL_STATUS_NOMEM;
- goto failed;
- }
}
if (!set_auth_type(conn->device, cmd->auth_req)) {
@@ -3502,9 +3348,6 @@ static struct desc_data *create_desc_data(int32_t conn_id,
struct desc_data *d;
d = new0(struct desc_data, 1);
- if (!d)
- return NULL;
-
d->conn_id = conn_id;
d->srvc_id = s_id;
d->char_id = ch_id;
@@ -3564,12 +3407,6 @@ static void handle_client_read_descriptor(const void *buf, uint16_t len)
cb_data = create_desc_data(conn_id, &srvc->id, &ch->id, &descr->id,
primary);
- if (!cb_data) {
- error("gatt: Read descr. could not allocate callback data");
-
- status = HAL_STATUS_NOMEM;
- goto failed;
- }
if (!set_auth_type(conn->device, cmd->auth_req)) {
error("gatt: Failed to set security %d", cmd->auth_req);
@@ -3693,16 +3530,9 @@ static void handle_client_write_descriptor(const void *buf, uint16_t len)
goto failed;
}
- if (cmd->write_type != GATT_WRITE_TYPE_NO_RESPONSE) {
+ if (cmd->write_type != GATT_WRITE_TYPE_NO_RESPONSE)
cb_data = create_desc_data(conn_id, &srvc->id, &ch->id,
&descr->id, primary);
- if (!cb_data) {
- error("gatt: Write descr. could not allocate cb_data");
-
- status = HAL_STATUS_NOMEM;
- goto failed;
- }
- }
if (!set_auth_type(conn->device, cmd->auth_req)) {
error("gatt: Failed to set security %d", cmd->auth_req);
@@ -3892,10 +3722,6 @@ static void handle_client_register_for_notification(const void *buf,
}
notification = new0(struct notification_data, 1);
- if (!notification) {
- status = HAL_STATUS_NOMEM;
- goto failed;
- }
memcpy(&notification->ch, &cmd->char_id, sizeof(notification->ch));
memcpy(&notification->service, &cmd->srvc_id,
@@ -3942,11 +3768,7 @@ static void handle_client_register_for_notification(const void *buf,
*/
notification->ref = 2;
- if (!queue_push_tail(conn->app->notifications, notification)) {
- unregister_notification(notification);
- status = HAL_STATUS_FAILED;
- goto failed;
- }
+ queue_push_tail(conn->app->notifications, notification);
status = HAL_STATUS_SUCCESS;
@@ -4498,8 +4320,6 @@ static void send_dev_complete_response(struct gatt_device *device,
struct queue *temp;
temp = queue_new();
- if (!temp)
- goto done;
val = queue_pop_head(device->pending_requests);
if (!val) {
@@ -4562,8 +4382,6 @@ static void send_dev_complete_response(struct gatt_device *device,
struct queue *temp;
temp = queue_new();
- if (!temp)
- goto done;
val = queue_pop_head(device->pending_requests);
if (!val) {
@@ -4625,12 +4443,6 @@ static void send_dev_complete_response(struct gatt_device *device,
}
range = new0(struct att_range, 1);
- if (!range) {
- destroy_pending_request(val);
- error = ATT_ECODE_INSUFF_RESOURCES;
- break;
- }
-
range->start = gatt_db_attribute_get_handle(
val->attrib);
@@ -4873,19 +4685,13 @@ static struct pending_trans_data *conn_add_transact(struct app_connection *conn,
static int32_t trans_id = 1;
transaction = new0(struct pending_trans_data, 1);
- if (!transaction)
- return NULL;
-
- if (!queue_push_tail(conn->transactions, transaction)) {
- free(transaction);
- return NULL;
- }
-
transaction->id = trans_id++;
transaction->opcode = opcode;
transaction->attrib = attrib;
transaction->serial_id = serial_id;
+ queue_push_tail(conn->transactions, transaction);
+
return transaction;
}
@@ -4944,8 +4750,6 @@ static void read_cb(struct gatt_db_attribute *attrib, unsigned int id,
/* Store the request data, complete callback and transaction id */
transaction = conn_add_transact(conn, opcode, attrib, id);
- if (!transaction)
- goto failed;
bdaddr2android(&bdaddr, ev.bdaddr);
ev.conn_id = conn->id;
@@ -5004,8 +4808,6 @@ static void write_cb(struct gatt_db_attribute *attrib, unsigned int id,
/* Store the request data, complete callback and transaction id */
transaction = conn_add_transact(conn, opcode, attrib, id);
- if (!transaction)
- goto failed;
memset(ev, 0, sizeof(*ev));
@@ -5308,9 +5110,6 @@ static struct service_sdp *new_service_sdp_record(int32_t service_handle)
return NULL;
s = new0(struct service_sdp, 1);
- if (!s)
- return NULL;
-
s->service_handle = service_handle;
s->sdp_handle = add_sdp_record(&uuid, service_handle, end_handle, NULL);
if (!s->sdp_handle) {
@@ -5345,10 +5144,7 @@ static bool add_service_sdp_record(int32_t service_handle)
if (!s)
return false;
- if (!queue_push_tail(services_sdp, s)) {
- free_service_sdp_record(s);
- return false;
- }
+ queue_push_tail(services_sdp, s);
return true;
}
@@ -6075,8 +5871,6 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len,
return ATT_ECODE_INVALID_HANDLE;
q = queue_new();
- if (!q)
- return ATT_ECODE_INSUFF_RESOURCES;
switch (cmd[0]) {
case ATT_OP_READ_BY_TYPE_REQ:
@@ -6099,17 +5893,8 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len,
struct gatt_db_attribute *attrib = queue_pop_head(q);
data = new0(struct pending_request, 1);
- if (!data) {
- queue_destroy(q, NULL);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
-
data->attrib = attrib;
- if (!queue_push_tail(device->pending_requests, data)) {
- free(data);
- queue_destroy(q, NULL);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ queue_push_tail(device->pending_requests, data);
}
queue_destroy(q, NULL);
@@ -6151,15 +5936,9 @@ static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len,
return ATT_ECODE_INVALID_HANDLE;
data = new0(struct pending_request, 1);
- if (!data)
- return ATT_ECODE_INSUFF_RESOURCES;
-
data->offset = offset;
data->attrib = attrib;
- if (!queue_push_tail(dev->pending_requests, data)) {
- free(data);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ queue_push_tail(dev->pending_requests, data);
process_dev_pending_requests(dev, cmd[0]);
@@ -6221,8 +6000,6 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
return ATT_ECODE_INVALID_HANDLE;
q = queue_new();
- if (!q)
- return ATT_ECODE_UNLIKELY;
gatt_db_find_information(gatt_db, start, end, q);
@@ -6232,10 +6009,6 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
}
temp = queue_new();
- if (!temp) {
- queue_destroy(q, NULL);
- return ATT_ECODE_UNLIKELY;
- }
attrib = queue_peek_head(q);
/* UUIDS can be only 128 bit and 16 bit */
@@ -6316,11 +6089,6 @@ static void find_by_type_request_cb(struct gatt_db_attribute *attrib,
return;
request_data = new0(struct pending_request, 1);
- if (!request_data) {
- find_data->error = ATT_ECODE_INSUFF_RESOURCES;
- return;
- }
-
request_data->filter_value = malloc0(find_data->search_vlen);
if (!request_data->filter_value) {
destroy_pending_request(request_data);
@@ -6333,11 +6101,7 @@ static void find_by_type_request_cb(struct gatt_db_attribute *attrib,
memcpy(request_data->filter_value, find_data->search_value,
find_data->search_vlen);
- if (!queue_push_tail(find_data->device->pending_requests,
- request_data)) {
- destroy_pending_request(request_data);
- find_data->error = ATT_ECODE_INSUFF_RESOURCES;
- }
+ queue_push_tail(find_data->device->pending_requests, request_data);
}
static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
@@ -6506,7 +6270,6 @@ static void attribute_write_cb(struct gatt_db_attribute *attrib, int err,
data->attrib = attrib;
data->error = error;
-
data->completed = true;
}
@@ -6540,15 +6303,9 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len,
return error;
data = new0(struct pending_request, 1);
- if (!data)
- return ATT_ECODE_INSUFF_RESOURCES;
-
data->attrib = attrib;
- if (!queue_push_tail(dev->pending_requests, data)) {
- free(data);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ queue_push_tail(dev->pending_requests, data);
if (!gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0],
g_attrib_get_att(dev->attrib),
@@ -6595,16 +6352,10 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len,
return error;
data = new0(struct pending_request, 1);
- if (!data)
- return ATT_ECODE_INSUFF_RESOURCES;
-
data->attrib = attrib;
data->offset = offset;
- if (!queue_push_tail(dev->pending_requests, data)) {
- free(data);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ queue_push_tail(dev->pending_requests, data);
data->value = g_memdup(value, vlen);
data->length = vlen;
@@ -6636,10 +6387,6 @@ static void send_server_write_execute_notify(void *data, void *user_data)
ev->conn_id = conn->id;
transaction = conn_add_transact(conn, ATT_OP_EXEC_WRITE_REQ, NULL, 0);
- if (!transaction) {
- conn->wait_execute_write = false;
- return;
- }
ev->trans_id = transaction->id;
@@ -6669,13 +6416,8 @@ static uint8_t write_execute_request(const uint8_t *cmd, uint16_t cmd_len,
ev.exec_write = value;
data = new0(struct pending_request, 1);
- if (!data)
- return ATT_ECODE_INSUFF_RESOURCES;
- if (!queue_push_tail(dev->pending_requests, data)) {
- free(data);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ queue_push_tail(dev->pending_requests, data);
queue_foreach(app_connections, send_server_write_execute_notify, &ev);
send_dev_complete_response(dev, cmd[0]);
@@ -6769,10 +6511,6 @@ static void connect_confirm(GIOChannel *io, void *user_data)
dev = find_device_by_addr(&dst);
if (!dev) {
dev = create_device(&dst);
- if (!dev) {
- error("gatt: Could not create device");
- goto drop;
- }
} else {
if ((dev->state != DEVICE_DISCONNECTED) &&
!(dev->state == DEVICE_CONNECT_INIT &&
@@ -7222,9 +6960,8 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
services_sdp = queue_new();
gatt_db = gatt_db_new();
- if (!gatt_devices || !gatt_apps || !listen_apps || !app_connections ||
- !services_sdp || !gatt_db) {
- error("gatt: Failed to allocate memory for queues");
+ if (!gatt_db) {
+ error("gatt: Failed to allocate memory for database");
goto failed;
}
diff --git a/android/gatt.h b/android/gatt.h
index 3382df9b..3382df9b 100644..100755
--- a/android/gatt.h
+++ b/android/gatt.h
diff --git a/android/hal-a2dp-sink.c b/android/hal-a2dp-sink.c
index a0b7ed1c..a0b7ed1c 100644..100755
--- a/android/hal-a2dp-sink.c
+++ b/android/hal-a2dp-sink.c
diff --git a/android/hal-a2dp.c b/android/hal-a2dp.c
index f572875e..f572875e 100644..100755
--- a/android/hal-a2dp.c
+++ b/android/hal-a2dp.c
diff --git a/android/hal-audio-aptx.c b/android/hal-audio-aptx.c
index a8000759..a8000759 100644..100755
--- a/android/hal-audio-aptx.c
+++ b/android/hal-audio-aptx.c
diff --git a/android/hal-audio-sbc.c b/android/hal-audio-sbc.c
index 7ad3a6a5..7ad3a6a5 100644..100755
--- a/android/hal-audio-sbc.c
+++ b/android/hal-audio-sbc.c
diff --git a/android/hal-audio.c b/android/hal-audio.c
index 207101fa..207101fa 100644..100755
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
diff --git a/android/hal-audio.h b/android/hal-audio.h
index 2b47412f..2b47412f 100644..100755
--- a/android/hal-audio.h
+++ b/android/hal-audio.h
diff --git a/android/hal-avrcp-ctrl.c b/android/hal-avrcp-ctrl.c
index 46b77fd8..46b77fd8 100644..100755
--- a/android/hal-avrcp-ctrl.c
+++ b/android/hal-avrcp-ctrl.c
diff --git a/android/hal-avrcp.c b/android/hal-avrcp.c
index f935eda5..f935eda5 100644..100755
--- a/android/hal-avrcp.c
+++ b/android/hal-avrcp.c
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index e24f7d2a..66f4a377 100644..100755
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
+#include <errno.h>
#include <cutils/properties.h>
@@ -1103,6 +1104,11 @@ static int open_bluetooth(const struct hw_module_t *module, char const *name,
DBG("");
+ if (!dev) {
+ error("Failed to allocate memory for device");
+ return -ENOMEM;
+ }
+
memset(dev, 0, sizeof(bluetooth_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
diff --git a/android/hal-gatt.c b/android/hal-gatt.c
index f7217c78..f7217c78 100644..100755
--- a/android/hal-gatt.c
+++ b/android/hal-gatt.c
diff --git a/android/hal-handsfree-client.c b/android/hal-handsfree-client.c
index 93b5746b..93b5746b 100644..100755
--- a/android/hal-handsfree-client.c
+++ b/android/hal-handsfree-client.c
diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
index 279b26a4..3847901a 100644..100755
--- a/android/hal-handsfree.c
+++ b/android/hal-handsfree.c
@@ -153,6 +153,16 @@ static void handle_nrec(void *buf, uint16_t len, int fd)
#endif
}
+static void handle_wbs(void *buf, uint16_t len, int fd)
+{
+#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+ struct hal_ev_handsfree_wbs *ev = buf;
+
+ if (cbs->wbs_cb)
+ cbs->wbs_cb(ev->wbs, (bt_bdaddr_t *) (ev->bdaddr));
+#endif
+}
+
static void handle_chld(void *buf, uint16_t len, int fd)
{
struct hal_ev_handsfree_chld *ev = buf;
@@ -289,6 +299,8 @@ static const struct hal_ipc_handler ev_handlers[] = {
/* HAL_EV_HANDSFREE_HSP_KEY_PRESS */
{ handle_hsp_key_press, false,
sizeof(struct hal_ev_handsfree_hsp_key_press) },
+ /* HAL_EV_HANDSFREE_WBS */
+ { handle_wbs, false, sizeof(struct hal_ev_handsfree_wbs) },
};
static uint8_t get_mode(void)
diff --git a/android/hal-health.c b/android/hal-health.c
index 5d5b1113..5d5b1113 100644..100755
--- a/android/hal-health.c
+++ b/android/hal-health.c
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index 1a603269..1a603269 100644..100755
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
diff --git a/android/hal-ipc-api.txt b/android/hal-ipc-api.txt
index 503b47ad..e3b7798b 100644..100755
--- a/android/hal-ipc-api.txt
+++ b/android/hal-ipc-api.txt
@@ -1068,6 +1068,14 @@ Notifications:
Notification parameters: Remote address (6 octets)
+ Opcode 0x91 - WBS Command notification
+
+ Notification parameters: WBS types (1 octet)
+ Remote address (6 octets)
+
+ Valid WBS types: 0x00 = None
+ 0x01 = No
+ 0x02 = Yes
Bluetooth Advanced Audio HAL (ID 6)
Bluetooth Advanced Audio Sink HAL (ID 13)
diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index 363072cf..363072cf 100644..100755
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
diff --git a/android/hal-ipc.h b/android/hal-ipc.h
index 08ed7cc8..08ed7cc8 100644..100755
--- a/android/hal-ipc.h
+++ b/android/hal-ipc.h
diff --git a/android/hal-log.h b/android/hal-log.h
index 63ff61b1..63ff61b1 100644..100755
--- a/android/hal-log.h
+++ b/android/hal-log.h
diff --git a/android/hal-map-client.c b/android/hal-map-client.c
index adf04fce..adf04fce 100644..100755
--- a/android/hal-map-client.c
+++ b/android/hal-map-client.c
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 698f45ad..ea79fa7d 100644..100755
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -1638,6 +1638,12 @@ struct hal_ev_handsfree_hsp_key_press {
uint8_t bdaddr[6];
} __attribute__((packed));
+#define HAL_EV_HANDSFREE_WBS 0x91
+struct hal_ev_handsfree_wbs {
+ uint8_t wbs;
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
#define HAL_AVRCP_FEATURE_NONE 0x00
#define HAL_AVRCP_FEATURE_METADATA 0x01
#define HAL_AVRCP_FEATURE_ABSOLUTE_VOLUME 0x02
diff --git a/android/hal-pan.c b/android/hal-pan.c
index 61d44a93..61d44a93 100644..100755
--- a/android/hal-pan.c
+++ b/android/hal-pan.c
diff --git a/android/hal-sco.c b/android/hal-sco.c
index 2c95866e..2c95866e 100644..100755
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
diff --git a/android/hal-socket.c b/android/hal-socket.c
index cfd50d15..cfd50d15 100644..100755
--- a/android/hal-socket.c
+++ b/android/hal-socket.c
diff --git a/android/hal-utils.c b/android/hal-utils.c
index e45f6e4a..e45f6e4a 100644..100755
--- a/android/hal-utils.c
+++ b/android/hal-utils.c
diff --git a/android/hal-utils.h b/android/hal-utils.h
index 9c599485..9c599485 100644..100755
--- a/android/hal-utils.h
+++ b/android/hal-utils.h
diff --git a/android/hal.h b/android/hal.h
index 709c1975..709c1975 100644..100755
--- a/android/hal.h
+++ b/android/hal.h
diff --git a/android/handsfree-client.c b/android/handsfree-client.c
index 0e2bd40a..65659b89 100644..100755
--- a/android/handsfree-client.c
+++ b/android/handsfree-client.c
@@ -177,14 +177,6 @@ static struct device *device_create(const bdaddr_t *bdaddr)
struct device *dev;
dev = new0(struct device, 1);
- if (!dev)
- return NULL;
-
- if (!queue_push_tail(devices, dev)) {
- error("hf-client: Could not push dev on the list");
- free(dev);
- return NULL;
- }
bacpy(&dev->bdaddr, bdaddr);
dev->state = HAL_HF_CLIENT_CONN_STATE_DISCONNECTED;
@@ -192,6 +184,8 @@ static struct device *device_create(const bdaddr_t *bdaddr)
init_codecs(dev);
+ queue_push_tail(devices, dev);
+
return dev;
}
@@ -2166,10 +2160,6 @@ bool bt_hf_client_register(struct ipc *ipc, const bdaddr_t *addr)
DBG("");
devices = queue_new();
- if (!devices) {
- error("hf-client: Could not create devices list");
- goto failed;
- }
bacpy(&adapter_addr, addr);
diff --git a/android/handsfree-client.h b/android/handsfree-client.h
index 1eb69ff3..1eb69ff3 100644..100755
--- a/android/handsfree-client.h
+++ b/android/handsfree-client.h
diff --git a/android/handsfree.c b/android/handsfree.c
index f1ad5feb..cb348ab9 100644..100755
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -228,8 +228,6 @@ static struct hf_device *device_create(const bdaddr_t *bdaddr)
struct hf_device *dev;
dev = new0(struct hf_device, 1);
- if (!dev)
- return NULL;
bacpy(&dev->bdaddr, bdaddr);
dev->setup_state = HAL_HANDSFREE_CALL_STATE_IDLE;
@@ -240,10 +238,7 @@ static struct hf_device *device_create(const bdaddr_t *bdaddr)
init_codecs(dev);
- if (!queue_push_head(devices, dev)) {
- free(dev);
- return NULL;
- }
+ queue_push_head(devices, dev);
return dev;
}
@@ -1067,6 +1062,7 @@ static void at_cmd_bcs(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
struct hf_device *dev = user_data;
+ struct hal_ev_handsfree_wbs ev;
unsigned int val;
DBG("");
@@ -1085,6 +1081,12 @@ static void at_cmd_bcs(struct hfp_context *result, enum hfp_gw_cmd_type type,
break;
}
+ ev.wbs = val;
+ bdaddr2android(&dev->bdaddr, ev.bdaddr);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
+ HAL_EV_HANDSFREE_WBS, sizeof(ev), &ev);
+
dev->proposed_codec = 0;
dev->negotiated_codec = val;
@@ -2924,7 +2926,7 @@ failed:
static const struct ipc_handler sco_handlers[] = {
/* SCO_OP_GET_FD */
- { bt_sco_get_fd, false, 0 }
+ { bt_sco_get_fd, false, sizeof(struct sco_cmd_get_fd) }
};
static void bt_sco_unregister(void)
@@ -2961,8 +2963,6 @@ bool bt_handsfree_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode,
return false;
devices = queue_new();
- if (!devices)
- return false;
if (!enable_hsp_ag())
goto failed_queue;
diff --git a/android/handsfree.h b/android/handsfree.h
index d4fd649b..d4fd649b 100644..100755
--- a/android/handsfree.h
+++ b/android/handsfree.h
diff --git a/android/health.c b/android/health.c
index f2895a29..eb02a64a 100644..100755
--- a/android/health.c
+++ b/android/health.c
@@ -822,9 +822,6 @@ static struct health_app *create_health_app(const char *app_name,
DBG("");
app = new0(struct health_app, 1);
- if (!app)
- return NULL;
-
app->id = app_id++;
app->num_of_mdep = mdeps;
app->app_name = strdup(app_name);
@@ -848,12 +845,7 @@ static struct health_app *create_health_app(const char *app_name,
}
app->mdeps = queue_new();
- if (!app->mdeps)
- goto fail;
-
app->devices = queue_new();
- if (!app->devices)
- goto fail;
return app;
@@ -906,8 +898,7 @@ static void bt_health_register_app(const void *buf, uint16_t len)
if (!app)
goto fail;
- if (!queue_push_tail(apps, app))
- goto fail;
+ queue_push_tail(apps, app);
rsp.app_id = app->id;
ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_REG_APP,
@@ -948,11 +939,6 @@ static void bt_health_mdep_cfg_data(const void *buf, uint16_t len)
}
mdep = new0(struct mdep_cfg, 1);
- if (!mdep) {
- status = HAL_STATUS_INVALID;
- goto fail;
- }
-
mdep->role = cmd->role;
mdep->data_type = cmd->data_type;
mdep->channel_type = android2channel_type(cmd->channel_type);
@@ -963,10 +949,7 @@ static void bt_health_mdep_cfg_data(const void *buf, uint16_t len)
memcpy(mdep->descr, cmd->descr, cmd->descr_len);
}
- if (!queue_push_tail(app->mdeps, mdep)) {
- status = HAL_STATUS_FAILED;
- goto fail;
- }
+ queue_push_tail(app->mdeps, mdep);
if (app->num_of_mdep != queue_length(app->mdeps))
goto send_rsp;
@@ -1258,28 +1241,15 @@ static struct health_device *create_device(struct health_app *app,
{
struct health_device *dev;
- if (!app)
- return NULL;
-
/* create device and push it to devices queue */
dev = new0(struct health_device, 1);
- if (!dev)
- return NULL;
android2bdaddr(addr, &dev->dst);
dev->channels = queue_new();
- if (!dev->channels) {
- free_health_device(dev);
- return NULL;
- }
-
- if (!queue_push_tail(app->devices, dev)) {
- free_health_device(dev);
- return NULL;
- }
-
dev->app_id = app->id;
+ queue_push_tail(app->devices, dev);
+
return dev;
}
@@ -1314,34 +1284,24 @@ static struct health_channel *create_channel(struct health_app *app,
if (!mdep) {
if (mdep_index == MDEP_ECHO) {
mdep = new0(struct mdep_cfg, 1);
- if (!mdep)
- return NULL;
/* Leave other configuration zeroes */
mdep->id = MDEP_ECHO;
- if (!queue_push_tail(app->mdeps, mdep)) {
- free_mdep_cfg(mdep);
- return NULL;
- }
- } else
+ queue_push_tail(app->mdeps, mdep);
+ } else {
return NULL;
+ }
}
/* create channel and push it to device */
channel = new0(struct health_channel, 1);
- if (!channel)
- return NULL;
-
channel->mdep_id = mdep->id;
channel->type = mdep->channel_type;
channel->id = channel_id++;
channel->dev = dev;
- if (!queue_push_tail(dev->channels, channel)) {
- free_health_channel(channel);
- return NULL;
- }
+ queue_push_tail(dev->channels, channel);
return channel;
}
@@ -1351,7 +1311,6 @@ static struct health_channel *connect_channel(struct health_app *app,
uint8_t mdepid)
{
struct health_device *device;
- struct health_channel *channel = NULL;
bdaddr_t addr;
DBG("app %p mdepid %u", app, mdepid);
@@ -1364,12 +1323,8 @@ static struct health_channel *connect_channel(struct health_app *app,
}
device = get_device(app, (uint8_t *) &addr);
- if (!device)
- return NULL;
- channel = create_channel(app, mdepid, device);
-
- return channel;
+ return create_channel(app, mdepid, device);
}
static uint8_t conf_to_l2cap(uint8_t conf)
@@ -1899,8 +1854,6 @@ static void bt_health_connect_channel(const void *buf, uint16_t len)
goto send_rsp;
dev = get_device(app, cmd->bdaddr);
- if (!dev)
- goto send_rsp;
channel = get_channel(app, cmd->mdep_index, dev);
if (!channel)
@@ -2076,8 +2029,6 @@ bool bt_health_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
hal_ipc = ipc;
apps = queue_new();
- if (!apps)
- return false;
ipc_register(hal_ipc, HAL_SERVICE_ID_HEALTH, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
diff --git a/android/health.h b/android/health.h
index 0b32fd31..0b32fd31 100644..100755
--- a/android/health.h
+++ b/android/health.h
diff --git a/android/hidhost.c b/android/hidhost.c
index 729b8847..591ca95a 100644..100755
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -44,13 +44,13 @@
#include "src/sdp-client.h"
#include "src/uuid-helper.h"
#include "src/log.h"
+#include "profiles/input/hog-lib.h"
#include "hal-msg.h"
#include "ipc-common.h"
#include "ipc.h"
#include "bluetooth.h"
#include "gatt.h"
-#include "hog.h"
#include "hidhost.h"
#include "utils.h"
@@ -891,7 +891,7 @@ static void bt_hid_connect(const void *buf, uint16_t len)
ba2str(&dev->dst, addr);
DBG("connecting to %s", addr);
- if (bt_is_device_le(&dst)) {
+ if (bt_device_last_seen_bearer(&dev->dst) != BDADDR_BREDR) {
if (!hog_connect(dev)) {
status = HAL_STATUS_FAILED;
hid_device_remove(dev);
diff --git a/android/hidhost.h b/android/hidhost.h
index e6b87ed2..e6b87ed2 100644..100755
--- a/android/hidhost.h
+++ b/android/hidhost.h
diff --git a/android/hog.c b/android/hog.c
index ff77bb37..ff77bb37 100644..100755
--- a/android/hog.c
+++ b/android/hog.c
diff --git a/android/hog.h b/android/hog.h
index 2a9b899c..2a9b899c 100644..100755
--- a/android/hog.h
+++ b/android/hog.h
diff --git a/android/init.bluetooth.rc b/android/init.bluetooth.rc
index 2d43f73b..2d43f73b 100644..100755
--- a/android/init.bluetooth.rc
+++ b/android/init.bluetooth.rc
diff --git a/android/ipc-common.h b/android/ipc-common.h
index 27736e4d..27736e4d 100644..100755
--- a/android/ipc-common.h
+++ b/android/ipc-common.h
diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 1aa17d25..1aa17d25 100644..100755
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
diff --git a/android/ipc.c b/android/ipc.c
index 2e674284..2e674284 100644..100755
--- a/android/ipc.c
+++ b/android/ipc.c
diff --git a/android/ipc.h b/android/ipc.h
index fd2b9852..fd2b9852 100644..100755
--- a/android/ipc.h
+++ b/android/ipc.h
diff --git a/android/log.c b/android/log.c
index 8013eba6..35917c60 100644..100755
--- a/android/log.c
+++ b/android/log.c
@@ -139,7 +139,7 @@ void error(const char *format, ...)
va_end(ap);
}
-void btd_debug(const char *format, ...)
+void btd_debug(uint16_t index, const char *format, ...)
{
va_list ap;
diff --git a/android/main.c b/android/main.c
index 03c8760b..03c8760b 100644..100755
--- a/android/main.c
+++ b/android/main.c
diff --git a/android/map-client.c b/android/map-client.c
index e3ad148a..e3ad148a 100644..100755
--- a/android/map-client.c
+++ b/android/map-client.c
diff --git a/android/map-client.h b/android/map-client.h
index 0e63072f..0e63072f 100644..100755
--- a/android/map-client.h
+++ b/android/map-client.h
diff --git a/android/pan.c b/android/pan.c
index a1b173b5..c40a6d3e 100644..100755
--- a/android/pan.c
+++ b/android/pan.c
@@ -88,7 +88,7 @@ static int set_forward_delay(int sk)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, BNEP_BRIDGE, IFNAMSIZ);
+ strncpy(ifr.ifr_name, BNEP_BRIDGE, IFNAMSIZ - 1);
ifr.ifr_data = (char *) args;
if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0) {
@@ -471,17 +471,11 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
sk = g_io_channel_unix_get_fd(chan);
-#ifndef __TIZEN_PATCH__
- /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
- n = read(sk, packet, sizeof(packet));
-#else
/*
* BNEP_SETUP_CONNECTION_REQUEST_MSG should be read and left in case
* of kernel setup connection msg handling.
*/
n = recv(sk, packet, sizeof(packet), MSG_PEEK);
-#endif
-
if (n < 0) {
error("read(): %s(%d)", strerror(errno), errno);
goto failed;
diff --git a/android/pan.h b/android/pan.h
index cfbea96a..cfbea96a 100644..100755
--- a/android/pan.h
+++ b/android/pan.h
diff --git a/android/pics-a2dp.txt b/android/pics-a2dp.txt
index 1328e7e4..2e87104d 100644..100755
--- a/android/pics-a2dp.txt
+++ b/android/pics-a2dp.txt
@@ -1,6 +1,6 @@
A2DP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -76,8 +76,8 @@ TSPC_A2DP_3_6 False SRC: MPEG-2,4 AAC encoder (C.1)
TSPC_A2DP_3_7 False SRC: ATRAC family decoder (C.1)
TSPC_A2DP_3_8 False SRC: ATRAC family encoder (C.1)
-------------------------------------------------------------------------------
-C.1: At least one of the implementations shall be supported if 12/2 (Optional
- codec) is supported, else excluded.
+C.1: At least one of the implementations shall be supported if 3/2
+ is supported, else excluded.
-------------------------------------------------------------------------------
@@ -138,8 +138,8 @@ TSPC_A2DP_5_3 False SNK: MPEG-1,2 Audio (C.1)
TSPC_A2DP_5_4 False SNK: MPEG-2,4 AAC (C.1)
TSPC_A2DP_5_5 False SNK: ATRAC family (C.1)
-------------------------------------------------------------------------------
-C.1: At least one codec shall be supported if Table 13/2 (Optional codec
- decoder) is supported, otherwise excluded.
+C.1: At least one codec shall be supported if Table 5/2 is supported, otherwise
+ excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-avctp.txt b/android/pics-avctp.txt
index 4fc599fa..34479623 100644..100755
--- a/android/pics-avctp.txt
+++ b/android/pics-avctp.txt
@@ -1,6 +1,6 @@
AVCTP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-avdtp.txt b/android/pics-avdtp.txt
index 191eaa47..c0c55295 100644..100755
--- a/android/pics-avdtp.txt
+++ b/android/pics-avdtp.txt
@@ -1,6 +1,6 @@
AVDTP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -27,7 +27,7 @@ Parameter Name Selected Description
TSPC_AVDTP_1_1 True (*) Source (C.1)
TSPC_AVDTP_1_2 True (*) Sink (C.1)
TSPC_AVDTP_1_3 True (*) Initiator (C.2)
-TSPC_AVDTP_1_4 True (*) Aceptor (C.2)
+TSPC_AVDTP_1_4 True (*) Acceptor (C.2)
-------------------------------------------------------------------------------
C.1: It is mandatory to support at least one of the defined roles.
C.2: It is within the scope of profiles using the AVDTP specification to
@@ -67,7 +67,8 @@ TSPC_AVDTP_4_4 True (*) Get configuration command (O)
TSPC_AVDTP_4_5 False Reconfigure command (O)
TSPC_AVDTP_4_6 True (*) Stream get all capabilities command (C.1)
-------------------------------------------------------------------------------
-C.1: It is optional to support if AVDTP 1.3 is supported, otherwise excluded.
+C.1: It is optional to support if TSPC_AVDTP_0_3 is supported, otherwise
+ excluded.
C.2: Mandatory to support if TSPC_AVDTP_4_6 is supported, otherwise Optional.
-------------------------------------------------------------------------------
@@ -131,7 +132,8 @@ TSPC_AVDTP_10_4 True (*) Get configuration response (O)
TSPC_AVDTP_10_5 False Reconfigure response (O)
TSPC_AVDTP_10_6 True (*) Stream get all capabilities response (C.1)
-------------------------------------------------------------------------------
-C.1: It is optional to support if AVDTP 1.3 is supported, otherwise excluded.
+C.1: It is optional to support if TSPC_AVDTP_0_3 is supported, otherwise
+ excluded.
C.2: It is Mandatory to support if TSPC_AVDTP_10_6 is supported, otherwise
Optional.
-------------------------------------------------------------------------------
@@ -177,7 +179,7 @@ TSPC_AVDTP_14_4 False Multiplexing service support (O)
TSPC_AVDTP_14_5 False Robust header compression service support (O)
TSPC_AVDTP_14_6 True (*) Delay Reporting (C.1)
-------------------------------------------------------------------------------
-C.1: It is optional to support if AVDTP 1.3 is supported, else excluded.
+C.1: It is optional to support if TSPC_AVDTP_0_3 is supported, else excluded.
-------------------------------------------------------------------------------
@@ -192,7 +194,7 @@ TSPC_AVDTP_15_4 False Multiplexing service support (O)
TSPC_AVDTP_15_5 False Robust header compression service support (O)
TSPC_AVDTP_15_6 True (*) Delay Reporting (C.1)
-------------------------------------------------------------------------------
-C.1: It is optional to support if AVDTP 1.3 is supported, else excluded.
+C.1: It is optional to support if TSPC_AVDTP_0_3 is supported, else excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-avrcp.txt b/android/pics-avrcp.txt
index a25579e7..7bd68fa7 100644..100755
--- a/android/pics-avrcp.txt
+++ b/android/pics-avrcp.txt
@@ -1,6 +1,6 @@
AVRCP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -12,7 +12,7 @@ O - optional
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-SPC_AVRCP_1_1 True (*) Role: Controller (CT) (C.1)
+TSPC_AVRCP_1_1 True (*) Role: Controller (CT) (C.1)
TSPC_AVRCP_1_2 True (*) Role: Target (TG) (C.1)
-------------------------------------------------------------------------------
C.1: Mandatory to support at least one of the defined roles.
diff --git a/android/pics-bnep.txt b/android/pics-bnep.txt
index 09aa725e..289e4705 100644..100755
--- a/android/pics-bnep.txt
+++ b/android/pics-bnep.txt
@@ -1,6 +1,6 @@
BNEP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-did.txt b/android/pics-did.txt
index da2e0903..9ecb86d1 100644..100755
--- a/android/pics-did.txt
+++ b/android/pics-did.txt
@@ -1,6 +1,6 @@
DID PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-dis.txt b/android/pics-dis.txt
index ed207c8d..83f25ce3 100644..100755
--- a/android/pics-dis.txt
+++ b/android/pics-dis.txt
@@ -1,6 +1,6 @@
DIS PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
@@ -14,7 +14,7 @@ Parameter Name Selected Description
TSPC_DIS_1_1 True Service supported over BR/EDR (C.1)
TSPC_DIS_1_2 True Service supported over LE (C.1)
-------------------------------------------------------------------------------
-C.1: Mandatory to support at least one of 1/1 or 1/2.
+C.1: Mandatory to support at least one of TSPC_DIS_1_1 or TSPC_DIS_1_2.
-------------------------------------------------------------------------------
@@ -35,7 +35,7 @@ TSPC_DIS_2_9 False (*) IEEE 11073-20601 Regulatory Certification
TSPC_DIS_2_10 True SDP Interoperability (C.1)
TSPC_DIS_2_11 True PnP ID (O)
-------------------------------------------------------------------------------
-C.1: Mandatory if 1/1 (BR/EDR) is supported, otherwise excluded.
+C.1: Mandatory if TSPC_DIS_1_1 (BR/EDR) is supported, otherwise excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-gap.txt b/android/pics-gap.txt
index 466f451e..37759955 100644..100755
--- a/android/pics-gap.txt
+++ b/android/pics-gap.txt
@@ -1,6 +1,6 @@
GAP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
@@ -63,11 +63,16 @@ TSPC_GAP_1_4 True Non-connectable mode (O)
TSPC_GAP_1_5 True Connectable mode (M)
TSPC_GAP_1_6 True Non-bondable mode (O)
TSPC_GAP_1_7 True Bondable mode (C.2)
-TSPC_GAP_1_8 False (*) Non-Synchronizable Mode (O)
-TSPC_GAP_1_9 False (*) Synchronizable Mode (O)
+TSPC_GAP_1_8 False (*) Non-Synchronizable Mode (C.3)
+TSPC_GAP_1_9 False (*) Synchronizable Mode (C.4)
-------------------------------------------------------------------------------
C.1: Mandatory if TSPC_GAP_0_2 is supported, otherwise Optional.
C.2: Mandatory if TSPC_GAP_3_5 is supported, otherwise Optional.
+C.3: Mandatory if TSPC_GAP_0A_2 or TSPC_GAP_0A_3 and is supported, otherwise
+ Excluded.
+C.4: Optional if TSPC_GAP_0A_2 or later is supported; Mandatory if TSPC_GAP_0A_2
+ or later and BB 3a/1 (Connectionless Slave Broadcast Transmitter) are
+ supported, otherwise Excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-gatt.txt b/android/pics-gatt.txt
index ec59853c..90585f5e 100644..100755
--- a/android/pics-gatt.txt
+++ b/android/pics-gatt.txt
@@ -1,6 +1,6 @@
GATT PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
@@ -13,8 +13,8 @@ Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_GATT_1_1 True Generic Attribute Profile Client (C.1)
TSPC_GATT_1_2 True Generic Attribute Profile Server (C.2)
-TSPC_GATT_1_3 True Complete GATT client (C.3)
-TSPC_GATT_1_4 True Complete GATT server (C.4)
+TSPC_GATT_1A_1 True Complete GATT client (C.3)
+TSPC_GATT_1A_2 True Complete GATT server (C.4)
-------------------------------------------------------------------------------
C.1: Optional to support IF TSPC_GATT_2_2; else IF TSPC_GATT_2_1 it is mandatory
to support at least one of TSPC_GATT_1_1 OR TSPC_GATT_1_2
@@ -248,15 +248,6 @@ C.2: Optional IF TSPC_GATT_2_2 is supported, otherwise Excluded
-------------------------------------------------------------------------------
- Attribute Protocol Client Messages
--------------------------------------------------------------------------------
-Parameter Name Selected Description
--------------------------------------------------------------------------------
-TSPC_GATT_8_1 True Support for Multiple ATT bearers from same
- device (O)
--------------------------------------------------------------------------------
-
-
Attribute Protocol Client Messages
-------------------------------------------------------------------------------
Parameter Name Selected Description
diff --git a/android/pics-gavdp.txt b/android/pics-gavdp.txt
index 1cf12a9b..8fa5ac17 100644..100755
--- a/android/pics-gavdp.txt
+++ b/android/pics-gavdp.txt
@@ -1,6 +1,6 @@
GAVDP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -12,10 +12,11 @@ O - optional
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_GAVDP_1_1 True (*) Initiator (O.1)
-TSPC_GAVDP_1_2 True (*) Initiator (O.1)
+TSPC_GAVDP_1_1 True (*) Initiator (C.1)
+TSPC_GAVDP_1_2 True (*) Initiator (C.1)
+-------------------------------------------------------------------------------
+C.1: Mandatory if Acceptor/Initiator is not supported
-------------------------------------------------------------------------------
-
GAVDP Procedures (Initiator)
-------------------------------------------------------------------------------
@@ -31,7 +32,7 @@ TSPC_GAVDP_2_3 False Transfer Control – Change Parameters (O)
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_GAVDP_2_1 True Connection Establishment (M)
-TSPC_GAVDP_2_2 True (*) Transfer Control -Suspend (O)
-TSPC_GAVDP_2_3 False Transfer Control – Change Parameters (O)
+TSPC_GAVDP_3_1 True Connection Establishment (M)
+TSPC_GAVDP_3_2 True (*) Transfer Control -Suspend (O)
+TSPC_GAVDP_3_3 False Transfer Control – Change Parameters (O)
-------------------------------------------------------------------------------
diff --git a/android/pics-hdp.txt b/android/pics-hdp.txt
index 2f293203..a613c971 100644..100755
--- a/android/pics-hdp.txt
+++ b/android/pics-hdp.txt
@@ -1,6 +1,6 @@
HDP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-hfp.txt b/android/pics-hfp.txt
index ea81289b..c658a252 100644..100755
--- a/android/pics-hfp.txt
+++ b/android/pics-hfp.txt
@@ -1,6 +1,6 @@
HFP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -195,7 +195,7 @@ TSPC_HFP_4_2 True (*) CVSD audio coding over eSCO (Accepting) (C.2)
-------------------------------------------------------------------------------
C.1: Mandatory if Wide band speech service is supported TSPC_HFP_2_24 or
TSPC_HFP_3_24, otherwise excluded
-C.2: Mandatory IF TPSC_HFP_2_3b OR TSPC_HFP_3_3b; otherwise Excluded.
+C.2: Mandatory IF TPSC_HFP_2_3b OR TSPC_HFP_3_3b; otherwise Excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-hid.txt b/android/pics-hid.txt
index ffd0affd..875f9b77 100644..100755
--- a/android/pics-hid.txt
+++ b/android/pics-hid.txt
@@ -1,6 +1,6 @@
HID PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -24,13 +24,13 @@ O.1: It is Mandatory to support One of these roles.
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_HID_2_1 True (*) Host: Establish HID connection (M.1)
-TSPC_HID_2_2 True (*) Host: Accept HID connection (M.1)
-TSPC_HID_2_3 True (*) Host: Terminate HID connection (M.1)
-TSPC_HID_2_4 True (*) Host: Accept termination of HID connection (M.1)
-TSPC_HID_2_5 True (*) Host: Support for virtual cables (M.1)
-TSPC_HID_2_6 True (*) Host: HID initiated connection (M.1)
-TSPC_HID_2_7 True (*) Host: Host initiated connection (M.1)
+TSPC_HID_2_1 True (*) Host: Establish HID connection (C.4)
+TSPC_HID_2_2 True (*) Host: Accept HID connection (C.4)
+TSPC_HID_2_3 True (*) Host: Terminate HID connection (C.4)
+TSPC_HID_2_4 True (*) Host: Accept termination of HID connection (C.4)
+TSPC_HID_2_5 True (*) Host: Support for virtual cables (C.4)
+TSPC_HID_2_6 True (*) Host: HID initiated connection (C.4)
+TSPC_HID_2_7 True (*) Host: Host initiated connection (C.4)
TSPC_HID_2_8 True (*) Host: Host data transfer to HID (C.1)
TSPC_HID_2_9 True (*) Host: HID data transfer to Host (C.1)
TSPC_HID_2_10 False Host: Boot mode data transfer to Host (C.2)
@@ -44,11 +44,12 @@ TSPC_HID_2_14 False Host : Support for sending HCI_CONTROL with
TSPC_HID_2_15 False Host : Support for receiving HCI_CONTROL with
VIRTUAL_CABLE_UNPLUG (C.3)
-------------------------------------------------------------------------------
-M.1: Mandatory to support IF (TSPC_HID_1_1) supported.
-C.1: Optional for Boot Mode Only Hosts (TSPC_HID_1_3); otherwise Mandatory
- for Host Role (TSPC_HID_1_1).
+C.1: Optional for Boot Mode Only Hosts (TSPC_HID_1_3); Mandatory for Host Role
+ (TSPC_HID_1_1); OTHERWISE Excluded.
C.2: Mandatory for Boot Mode Only Hosts (TSPC_HID_1_3); otherwise Optional.
C.3: Optional IF (TSPC_HID_2_5) supported, otherwise excluded.
+C.4: Mandatory IF TSPC_HID_1_1 (Host, Report protocol) is supported, otherwise
+ Optional.
-------------------------------------------------------------------------------
@@ -57,15 +58,15 @@ C.3: Optional IF (TSPC_HID_2_5) supported, otherwise excluded.
Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_HID_3_1 False Host : Data reports larger than host MTU on
- Control channel (C.1)
+ Control channel (O)
TSPC_HID_3_2 True (*) Host : Data reports larger than host MTU on
Interrupt channel (C.1)
-TSPC_HID_3_3 True (*) Host : Data reports to host (C.2)
-TSPC_HID_3_4 False Host : Boot mode reports to host (O)
+TSPC_HID_3_3 True (*) Host : Data reports to host (C.1)
+TSPC_HID_3_4 False Host : Boot mode reports to host (C.2)
-------------------------------------------------------------------------------
-C.1: Excluded for Boot Mode Only Hosts (TSPC_HID_1_3); otherwise Optional
-C.2: Excluded for Boot Mode Only Hosts (TSPC_HID_1_3); otherwise Mandatory for
- Host Role (TSPC_HID_1_1)
+C.1: Excluded for Boot Mode Only Hosts (TSPC_HID_1_3); Mandatory IF
+ TSPC_HID_2_12 is supported, otherwise Optional.
+C.2: Mandatory IF TSPC_HID_1_3 is supported, otherwise Optional.
-------------------------------------------------------------------------------
@@ -97,9 +98,8 @@ TSPC_HID_5_4 False Host : Get_Idle command (O)
TSPC_HID_5_5 False Host : Set_Report command (C.2)
TSPC_HID_5_6 False Host : Get_Report command (C.3)
-------------------------------------------------------------------------------
-C.2: Mandatory IF (TSPC_HID_1_1) supported AND (TSPC_HID_2_13) supported.
C.1: Mandatory for Boot Mode Only Hosts (TSPC_HID_1_3); otherwise Optional.
- If either Set_Protocol or Get_Protocol supported, both are Mandatory.
+C.2: Mandatory IF (TSPC_HID_1_1) supported AND (TSPC_HID_2_13) supported.
C.3: Mandatory IF (TSPC_HID_1_1) Supported AND (TSPC_HID_2_12) Supported
C.4: Mandatory to support TSPC_HID_5_1 (Set_Protocol command) AND TSPC_HID_5_2
(Get_Protocol command) IF one of TSPC_HID_5_1 (Set_Protocol command)
@@ -123,19 +123,19 @@ TSPC_HID_6_4 False Host : Initiate pairing after connection
TSPC_HID_6_5 False Host : Encryption (O)
TSPC_HID_6_6 False Host : Initiate encryption (C.3)
TSPC_HID_6_7 False Host : Accept encryption requests (C.3)
-TSPC_HID_6_8 True (*) Host : Role switch (Master/Slave) (M.1)
-TSPC_HID_6_9 True (*) Host : Request Master Slave switch (M.1)
-TSPC_HID_6_10 True (*) Host : Accept Master Slave switch requests (M.1)
+TSPC_HID_6_8 True (*) Host : Role switch (Master/Slave) (C.4)
+TSPC_HID_6_9 True (*) Host : Request Master Slave switch (C.4)
+TSPC_HID_6_10 True (*) Host : Accept Master Slave switch requests (C.4)
TSPC_HID_6_11 False Host : Hold mode (O)
-TSPC_HID_6_12 True (*) Host : Sniff mode (M.1)
+TSPC_HID_6_12 True (*) Host : Sniff mode (C.4)
TSPC_HID_6_13 False Host : Park mode (O)
-------------------------------------------------------------------------------
-C.1: If Host Authentication supported, both (TSPC_HID_6_1) AND (TSPC_HID_6_2)
- must be supported.
+C.1: Mandatory to support TSPC_HID_6_1 AND TSPC_HID_6_2 IF GAP 2/3
+ (Initiate LMP-Authentication) is supported, otherwise Excluded.
C.2: If Pairing supported both (TSPC_HID_6_3) AND (TSPC_HID_6_4) must
be supported.
-M.1: Mandatory IF (TSPC_HID_1_1) supported.
C.3: Mandatory IF (TSPC_HID_6_5) encryption supported.
+C.4: Mandatory IF (TSPC_HID_1_1) supported, otherwise Excluded.
-------------------------------------------------------------------------------
@@ -143,10 +143,10 @@ C.3: Mandatory IF (TSPC_HID_6_5) encryption supported.
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_HID_7_1 True (*) Host : Supports inquiry, 79 channel (M.1)
+TSPC_HID_7_1 True (*) Host : Supports inquiry, 79 channel (C.1)
TSPC_HID_7_2 False Host : Supports inquiry scan, 79 channel (C.2)
-------------------------------------------------------------------------------
-M.1: Mandatory to support IF (TSPC_HID_1_1) supported.
+C.1: Mandatory to support IF (TSPC_HID_1_1) supported, otherwise Excluded.
C.2: Feature should not be used by a Host, but can be supported in LM.
-------------------------------------------------------------------------------
@@ -170,9 +170,9 @@ O.1: It is Mandatory to support One of these roles IF (TSPC_HID_1_2)
Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_HID_9_1 False Hid : Establish HID connection (O)
-TSPC_HID_9_2 False (*) Hid : Accept HID connection (M.1)
+TSPC_HID_9_2 False (*) Hid : Accept HID connection (M)
TSPC_HID_9_3 False Hid : Terminate HID connection (O)
-TSPC_HID_9_4 False (*) Hid : Accept Termination of HID connection (M.1)
+TSPC_HID_9_4 False (*) Hid : Accept Termination of HID connection (M)
TSPC_HID_9_5 False Hid : Support for virtual cables (O)
TSPC_HID_9_6 False Hid : HID initiated reconnection (C.1)
TSPC_HID_9_7 False Hid : Host initiated reconnection (C.1)
@@ -188,10 +188,9 @@ TSPC_HID_9_15 False Hid : Support for sending HCI_CONTROL with
TSPC_HID_9_16 False Hid : Support for receiving HCI_CONTROL with
VIRTUAL_CABLE_UNPLUG (C.5)
-------------------------------------------------------------------------------
-M.1: Mandatory IF (TSPC_HID_1_2) supported.
C.1: One of these is Mandatory IF (TSPC_HID_9_5) is supported
(SDP attribute 0x204=True)
-C.2: One of these is Mandatory.
+C.2: One of these is Mandatory if TSPC_HID_1_2 (HID Role) is supported.
C.3: Mandatory IF (TSPC_HID_8_1) OR (TSPC_HID_8_2) is selected
C.4: Mandatory IF (TSPC_HID_8_2) is supported (for status indicators)
C.5: Optional IF (TSPC_HID_9_5) supported, otherwise excluded.
diff --git a/android/pics-hogp.txt b/android/pics-hogp.txt
index e656e0cd..bd9c9f99 100644..100755
--- a/android/pics-hogp.txt
+++ b/android/pics-hogp.txt
@@ -1,6 +1,6 @@
HOGP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -13,13 +13,11 @@ O - optional
Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_HOGP_1_1 False (*) HID Device (Server) (C.1)
-TSPC_HOGP_1_2 True Report Host (Client) (C.1, C.2)
-TSPC_HOGP_1_3 False (*) Boot Host (Client) (C.1, C.3)
+TSPC_HOGP_1_2 True Report Host (Client) (C.1)
+TSPC_HOGP_1_3 False (*) Boot Host (Client) (C.1)
-------------------------------------------------------------------------------
C.1: Mandatory to support at least one of TSPC_HOGP_1_1 or TSPC_HOGP_1_2
or TSPC_HOGP_1_3.
-C.2: Excluded if TSPC_HOGP_1_3 is supported.
-C.3: Excluded if TSPC_HOGP_1_2 is supported.
-------------------------------------------------------------------------------
@@ -91,7 +89,8 @@ M.1: Mandatory if TSPC_HOGP_1_1 selected
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_HOGP_6_1 False (*) SM 2.3.1 (M.1)
+TSPC_HOGP_6_1 False (*) No security
+ (LE Security Level 1) (M.1)
TSPC_HOGP_6_2 False (*) Unauthenticated no MITM protection
(LE Security Level 2, Just Works) (M.1)
TSPC_HOGP_6_3 False (*) Authenticated MITM protection
@@ -335,24 +334,26 @@ C.2: Mandatory to support if TSPC_HOGP_10_8 is supported, else excluded.
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_HOGP_13_1 True Attribute Protocol supported over LE Transport (M)
-TSPC_HOGP_13_2 True Generic Attribute Profile Client (M)
+TSPC_HOGP_13_1 True Attribute Protocol supported over LE Transport
+ (M.1)
+TSPC_HOGP_13_2 True Generic Attribute Profile Client (M.1)
TSPC_HOGP_13_3 True Discover All Primary Services (C.1)
TSPC_HOGP_13_4 False (*) Discover Primary Services by Service UUID (C.1)
-TSPC_HOGP_13_5 True Find Included Services (M)
+TSPC_HOGP_13_5 True Find Included Services (M.1)
TSPC_HOGP_13_6 True Discover All Characteristics of a Service (C.2)
TSPC_HOGP_13_7 False (*) Discover Characteristics by UUID (C.2)
-TSPC_HOGP_13_8 True Discover All Characteristic Descriptors (M)
-TSPC_HOGP_13_9 True Read Characteristic Value (M)
+TSPC_HOGP_13_8 True Discover All Characteristic Descriptors (M.1)
+TSPC_HOGP_13_9 True Read Characteristic Value (M.1)
TSPC_HOGP_13_10 True Read using Characteristic UUID (O)
-TSPC_HOGP_13_11 True Read Long Characteristic Value (M)
-TSPC_HOGP_13_12 True Read Characteristic Descriptors (M)
-TSPC_HOGP_13_13 True Write without Response (M)
-TSPC_HOGP_13_14 True Write Characteristic Value (M)
-TSPC_HOGP_13_15 True Write Characteristic Descriptors (M)
-TSPC_HOGP_13_16 True Notifications (M)
-TSPC_HOGP_13_17 True Exchange MTU (M)
+TSPC_HOGP_13_11 True Read Long Characteristic Value (M.1)
+TSPC_HOGP_13_12 True Read Characteristic Descriptors (M.1)
+TSPC_HOGP_13_13 True Write without Response (M.1)
+TSPC_HOGP_13_14 True Write Characteristic Value (M.1)
+TSPC_HOGP_13_15 True Write Characteristic Descriptors (M.1)
+TSPC_HOGP_13_16 True Notifications (M.1)
+TSPC_HOGP_13_17 True Exchange MTU (M.1)
-------------------------------------------------------------------------------
+M.1: Mandatory if TSPC_HOGP_1_2 selected
C.1: Mandatory to support at least one of these features.
C.2: Mandatory to support at least one of these features.
-------------------------------------------------------------------------------
@@ -362,20 +363,23 @@ C.2: Mandatory to support at least one of these features.
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_HOGP_14_1 False (*) Attribute Protocol supported over LE Transport (M)
-TSPC_HOGP_14_2 False (*) Generic Attribute Profile Client (M)
+TSPC_HOGP_14_1 False (*) Attribute Protocol supported over LE Transport
+ (M.1)
+TSPC_HOGP_14_2 False (*) Generic Attribute Profile Client (M.1)
TSPC_HOGP_14_3 False (*) Discover All Primary Services (C.1)
TSPC_HOGP_14_4 False (*) Discover Primary Services by Service UUID (C.1)
TSPC_HOGP_14_5 False (*) Discover All Characteristics of a Service (O)
TSPC_HOGP_14_6 False (*) Discover Characteristics by UUID (O)
-TSPC_HOGP_14_7 False (*) Discover All Characteristic Descriptors (M)
-TSPC_HOGP_14_8 False (*) Read Characteristic Value (M)
-TSPC_HOGP_14_9 False (*) Read using Characteristic UUID (M)
-TSPC_HOGP_14_10 False (*) Read Characteristic Descriptors (M)
-TSPC_HOGP_14_11 False (*) Write without Response (M)
-TSPC_HOGP_14_12 False (*) Write Characteristic Value (M)
-TSPC_HOGP_14_13 False (*) Write Characteristic Descriptors (M)
-TSPC_HOGP_14_14 False (*) Notifications (M)
+TSPC_HOGP_14_7 False (*) Discover All Characteristic Descriptors (M.1)
+TSPC_HOGP_14_8 False (*) Read Characteristic Value (M.1)
+TSPC_HOGP_14_9 False (*) Read using Characteristic UUID (M.1)
+TSPC_HOGP_14_10 False (*) Read Characteristic Descriptors (M.1)
+TSPC_HOGP_14_11 False (*) Write without Response (M.1)
+TSPC_HOGP_14_12 False (*) Write Characteristic Value (M.1)
+TSPC_HOGP_14_13 False (*) Write Characteristic Descriptors (M.1)
+TSPC_HOGP_14_14 False (*) Notifications (M.1)
+-------------------------------------------------------------------------------
+M.1: Mandatory if TSPC_HOGP_1_3 selected
-------------------------------------------------------------------------------
@@ -383,11 +387,10 @@ TSPC_HOGP_14_14 False (*) Notifications (M)
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_HOGP_15_1 True Central (M.1 or M.2)
-TSPC_HOGP_15_2 True LE Security Mode 1 (central) (M.1 or M.2)
+TSPC_HOGP_15_1 True Central (M.1)
+TSPC_HOGP_15_2 True LE Security Mode 1 (central) (M.1)
-------------------------------------------------------------------------------
-M.1: Mandatory if TSPC_HOGP_1_2 selected
-M.2: Mandatory if TSPC_HOGP_1_3 selected
+M.1: Mandatory if TSPC_HOGP_1_2 or TSPC_HOGP_1_3 is selected
-------------------------------------------------------------------------------
@@ -396,9 +399,11 @@ M.2: Mandatory if TSPC_HOGP_1_3 selected
Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_HOGP_16_1 True No Security Requirements (LE Security Level 1,
- No Security) (M)
+ No Security) (M.1)
TSPC_HOGP_16_2 True Unauthenticated no MITM protection (LE Security
- Level 2, Just Works) (M)
+ Level 2, Just Works) (M.1)
TSPC_HOGP_16_3 True Authenticated MITM protection (LE Security
Level 3, Passkey) (O)
-------------------------------------------------------------------------------
+M.1: Mandatory if TSPC_HOGP_1_2 or TSPC_HOGP_1_3 is selected
+-------------------------------------------------------------------------------
diff --git a/android/pics-hsp.txt b/android/pics-hsp.txt
index 3818e74e..e55b986d 100644..100755
--- a/android/pics-hsp.txt
+++ b/android/pics-hsp.txt
@@ -1,6 +1,6 @@
HSP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-iopt.txt b/android/pics-iopt.txt
index 4d07d70e..7277c4ce 100644..100755
--- a/android/pics-iopt.txt
+++ b/android/pics-iopt.txt
@@ -1,6 +1,6 @@
IOPT PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-l2cap.txt b/android/pics-l2cap.txt
index 984116b1..ce50c98f 100644..100755
--- a/android/pics-l2cap.txt
+++ b/android/pics-l2cap.txt
@@ -1,6 +1,6 @@
L2CAP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -99,13 +99,11 @@ TSCP_L2CAP_2_47 True Support for LE Data Channel (C.24)
-------------------------------------------------------------------------------
C.1: Mandatory to support at least one of TSPC_L2CAP_2_12 OR TSPC_L2CAP_2_13 OR
TSPC_L2CAP_2_35 IF BR/EDR OR BR/EDR/LE AND SUM_ICS 31/7 (CSA1) OR
- Core Spec v3.0 OR Core Spec v3.0+HS OR Core Spec v4.0 OR
- Core Spec v4.0+HS OR Core Spec v4.1 OR Core Spec v4.1+HS OR
- Core Spec v4.2 OR Core Spec v4.2+HS is supported, ELSE Excluded
+ Core Spec v3.0 or later is supported, ELSE Excluded
C.2: Optional IF TSPC_L2CAP_2_12 OR TSPC_L2CAP_2_13 is claimed, ELSE Excluded.
C.3: Optional IF TSPC_L2CAP_2_12 AND TSPC_L2CAP_2_28 is claimed, ELSE Excluded.
C.4: IF TSPC_L2CAP_2_12 is claimed THEN either TSPC_L2CAP_2_18
- OR TSPC_L2CAP_2_20 are Mandatory, ELSE Excluded.
+ OR TSPC_L2CAP_2_20 is Mandatory, ELSE Excluded.
C.5: IF TSPC_L2CAP_2_13 is claimed THEN either TSPC_L2CAP_2_19
OR TSPC_L2CAP_2_21 are Mandatory, ELSE Excluded.
C.6: Optional IF TSPC_L2CAP_2_12 is claimed, ELSE Excluded.
@@ -119,16 +117,12 @@ C.12: Mandatory IF Core Spec v3.0+HS OR Core Spec v4.0+HS OR
Core Spec v4.1+HS OR Core Spec v4.2+HS is claimed, ELSE Optional.
C.13: Mandatory IF Core Spec v3.0+HS OR Core Spec v4.0+HS OR
Core Spec v4.1+HS OR Core Spec v4.2+HS is claimed, ELSE Optional.
-C.14: Optional IF Core Spec v3.0 OR Core Spec v3.0+HS OR Core Spec v4.0 OR
- Core Spec v4.0+HS OR Core Spec v4.1 OR Core Spec v4.1+HS OR
- Core Spec v4.2 OR Core Spec v4.2+HS is claimed, ELSE Excluded.
+C.14: Optional IF Core Spec v3.0 OR or later is claimed, ELSE Excluded.
C.15: Optional IF TSPC_L2CAP_2_29 is claimed, ELSE Excluded.
-C.16: Optional IF Core Spec v3.0 OR Core Spec v3.0+HS OR Core Spec v4.0 OR
- Core Spec v4.0+HS OR Core Spec v4.1 OR Core Spec v4.1+HS OR
- Core Spec v4.2 OR Core Spec v4.2+HS is claimed, ELSE Excluded.
+C.16: Optional IF Core Spec v3.0 or later is claimed, ELSE Excluded.
C.17: Mandatory IF LE OR BR/EDR/LE is claimed, ELSE Excluded.
-C.18: Optional IF TSPC_L2CAP_1_4 is claimed, ELSE Excluded.
-C.19: Mandatory IF TSPC_L2CAP_1_3 is claimed, ELSE Excluded.
+C.18: Optional IF Core Spec 4.0 OR TSPC_L2CAP_1_4 is claimed, ELSE Excluded.
+C.19: Mandatory IF Core Spec 4.0 AND TSPC_L2CAP_1_3 is claimed, ELSE Excluded.
C.20: Mandatory IF BR/EDR OR BR/EDR/LE, is claimed, ELSE Excluded
C.21: Optional IF BR/EDR OR BR/EDR/LE, is claimed, ELSE Excluded.
C.22: Mandatory IF TSPC_L2CAP_2_29 is claimed, ELSE Excluded.
@@ -167,7 +161,7 @@ TSPC_L2CAP_3_14 False (*) Negotiate and support service type ‘Best Effort'
TSPC_L2CAP_3_15 False (*) Negotiate and support service type ‘Guaranteed’
for Extended Flow Specification (C.9)
TSPC_L2CAP_3_16 True Support Multiple Simultaneous LE Data
- Channels (C.10)
+ Channels (C.10)
-------------------------------------------------------------------------------
C.1: Mandatory if TSPC_L2CAP_3_8 is supported, ELSE Optional.
C.2: Optional if TSPC_L2CAP_3_8 is supported, ELSE Excluded.
@@ -179,5 +173,6 @@ C.7: Optional if TSPC_L2CAP_2_44 OR TSPC_L2CAP_2_38 is supported, ELSE Excluded.
C.8: Mandatory if TSPC_L2CAP_2_44 OR TSPC_L2CAP_2_38 is supported,
ELSE Excluded.
C.9: Optional if TSPC_L2CAP_2_44 OR TSPC_L2CAP_2_38 is supported, ELSE Excluded.
-C.10: Optional IF TSPC_L2CAP_2_47 is supported, otherwise Excluded.
+C.10: Optional IF TSPC_L2CAP_2_47 AND Core Spec 4.1 is supported,
+ otherwise Excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-map.txt b/android/pics-map.txt
index 093aae16..b1346b63 100644..100755
--- a/android/pics-map.txt
+++ b/android/pics-map.txt
@@ -1,6 +1,6 @@
MAP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-mcap.txt b/android/pics-mcap.txt
index 70e0b66c..218ee804 100644..100755
--- a/android/pics-mcap.txt
+++ b/android/pics-mcap.txt
@@ -1,6 +1,6 @@
MCAP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -52,7 +52,7 @@ TSPC_MCAP_2_4 False Can support multiple simultaneous MCLs with
-------------------------------------------------------------------------------
Parameter Name Selected Description
-------------------------------------------------------------------------------
-TSPC_MCAP_3_1 This row inentionally left blank
+TSPC_MCAP_3_1 This row intentionally left blank
TSPC_MCAP_3_2 True (*) Initiate creation of Control and Data Channels
(C.1)
TSPC_MCAP_3_3 True (*) Accept creation of Control and Data Channels
diff --git a/android/pics-mps.txt b/android/pics-mps.txt
index 29b82a9b..5aad7c1a 100644..100755
--- a/android/pics-mps.txt
+++ b/android/pics-mps.txt
@@ -1,6 +1,6 @@
MPS PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -219,36 +219,34 @@ TSPC_MPS_6_37 True (*) A2DP-SRC_PBAP-Server Implementation Phonebook
TSPC_MPS_6_38 False A2DP-SNK and PBAP-Client Implementation
Phonebook Download during Audio Streaming (C.12)
TSPC_MPS_6_39 True (*) HFP-AG and PBAP-Server Implementation PBAP and
- HFP Connection Behavior (C.13)
--------------------------------------------------------------------------------
-C.1: Mandatory if 2/1 (A2DP Source role), 2/4 (AVRCP Target role) and 2/7
- (HFP Audio Gateway role) are supported, otherwise Excluded.
-C.2: Mandatory if 2/2 (A2DP Sink role), 2/3 (AVRCP Controller role) and 2/8
- (HFP Hands-Free role) are supported, otherwise Excluded.
-C.3: Mandatory if 2/5 (DUN Gateway role) and 2/7 (HFP Audio Gateway role)
- are supported and 3/9 ( Ability to support parallel data and call
- operation), otherwise Excluded.
-C.4: Mandatory if 2/6 (DUN Data Terminal role) and 2/8 (HFP Hands-Free role)
- are supported, otherwise Excluded.
-C.5: Mandatory if 2/1 (A2DP Source role) and 2/5 (DUN Gateway role) are
- supported, otherwise Excluded.
-C.6: Mandatory if 2/2 (A2DP Sink role) and 2/6 (DUN Data Terminal role) are
- supported, otherwise Excluded.
-C.7: Mandatory if 2/7 (HFP Audio Gateway role) and 2/9 (PAN Network Access Point
- role) and 3/11 (Ability to support parallel data and call operation) are
- supported, otherwise Excluded.
-C.8: Mandatory if 2/8 (HFP Hands-Free role) and 2/11 (PAN User role) are
- supported and 3/11, otherwise Excluded.
-C.9: Mandatory if 2/1 (A2DP Source role) and 2/9 (PAN Network Access Point role)
- are supported, otherwise Excluded.
-C.10: Mandatory if 2/2 (A2DP Sink role) and 2/11 (PAN User role) are supported,
+ HFP Connection Behaviour (C.13)
+-------------------------------------------------------------------------------
+C.1: Mandatory if TSPC_MPS_2_1, TSPC_MPS_2_4 and TSPC_MPS_2_7 are supported,
otherwise Excluded.
-C.11: Mandatory if 2/1 (A2DP Source role) and 2/13 (PBAP PSE role) are
- supported, otherwise Excluded.
-C.12: Mandatory if 2/2 (A2DP Sink role) and 2/12 (PBAP PCE role) are supported,
+C.2: Mandatory if TSPC_MPS_2_2, TSPC_MPS_2_3 and TSPC_MPS_2_8 are supported,
+ otherwise Excluded.
+C.3: Mandatory if TSPC_MPS_2_5 and TSPC_MPS_2_7 are supported and TSPC_MPS_3_9,
otherwise Excluded.
-C.13: Mandatory if 2/7 (HFP Audio Gateway role) and 2/13 (PBAP PSE role) are
+C.4: Mandatory if TSPC_MPS_2_6 and TSPC_MPS_2_8 are supported, otherwise
+ Excluded.
+C.5: Mandatory if TSPC_MPS_2_1 and TSPC_MPS_2_5 are supported, otherwise
+ Excluded.
+C.6: Mandatory if TSPC_MPS_2_2 and TSPC_MPS_2_6 are supported, otherwise
+ Excluded.
+C.7: Mandatory if TSPC_MPS_2_7 and TSPC_MPS_2_9 and TSPC_MPS_3_11 are
supported, otherwise Excluded.
+C.8: Mandatory if TSPC_MPS_2_8 and TSPC_MPS_2_11 are supported and
+ TSPC_MPS_3_11, otherwise Excluded.
+C.9: Mandatory if TSPC_MPS_2_1 and TSPC_MPS_2_9 are supported, otherwise
+ Excluded.
+C.10: Mandatory if TSPC_MPS_2_2 and TSPC_MPS_2_11 are supported, otherwise
+ Excluded.
+C.11: Mandatory if TSPC_MPS_2_1 and TSPC_MPS_2_13 are supported, otherwise
+ Excluded.
+C.12: Mandatory if TSPC_MPS_2_2 and TSPC_MPS_2_12 are supported, otherwise
+ Excluded.
+C.13: Mandatory if TSPC_MPS_2_7 and TSPC_MPS_2_13 are supported, otherwise
+ Excluded.
-------------------------------------------------------------------------------
@@ -293,12 +291,12 @@ TSPC_MPS_7_14 False A2DP-SNK and AVRCP-CT and DUN-DT Implementation
Start Packet Data Communication during Audio
Streaming (C.3)
-------------------------------------------------------------------------------
-C.1: Mandatory if 2/2 (A2DP Sink role), 2/3 (AVRCP Controller role) and 2/8
- (HFP Hands-Free role) are supported, otherwise Excluded.
-C.2: Mandatory if 2/1 (A2DP Source role) and 2/4 (AVRCP Target role) are
- supported, otherwise Excluded.
-C.3: Mandatory if 2/2 (A2DP Sink role), 2/3 (AVRCP Controller role) and 2/6
- (DUN Data Terminal role) supported, otherwise Excluded.
+C.1: Mandatory if TSPC_MPS_2_2, TSPC_MPS_2_3 and TSPC_MPS_2_8 are supported,
+ otherwise Excluded.
+C.2: Mandatory if TSPC_MPS_2_1 and TSPC_MPS_2_4 are supported, otherwise
+ Excluded.
+C.3: Mandatory if TSPC_MPS_2_2, TSPC_MPS_2_3 and 2/6TSPC_MPS_2_6 supported,
+ otherwise Excluded.
-------------------------------------------------------------------------------
@@ -307,12 +305,12 @@ C.3: Mandatory if 2/2 (A2DP Sink role), 2/3 (AVRCP Controller role) and 2/6
Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_MPS_8_1 True (*) AVP Suspension (C.1)
-TSPC_MPS_8_2 True (*) Profile (Dis-)Connection behavior (C.2)
+TSPC_MPS_8_2 True (*) Profile (Dis-)Connection behaviour (C.2)
-------------------------------------------------------------------------------
-C.1: Mandatory if 1/1 (A2DP 1.2 or later) and 1/2 (AVRCP 1.3 or later) are
- supported, otherwise Excluded.
-C.2: Mandatory if 1/1 (A2DP 1.2 or later), 1/2 (AVRCP 1.3 or later) and 1/4 (HFP
- 1.5 or later) are supported, otherwise Excluded.
+C.1: Mandatory if TSPC_MPS_1_1 and TSPC_MPS_1_2 are supported, otherwise
+ Excluded.
+C.2: Mandatory if TSPC_MPS_1_1, TSPC_MPS_1_2 and TSPC_MPS_1_4 are supported,
+ otherwise Excluded.
-------------------------------------------------------------------------------
@@ -333,7 +331,7 @@ TSPC_MPS_10_1 True SDP Record (M)
TSPC_MPS_10_2 True (*) Media Stream Suspension (C.1)
TSPC_MPS_10_3 True (*) Sniff Mode during Streaming (C.2)
-------------------------------------------------------------------------------
-C.1: Mandatory if 1/1 (A2DP1.2 or later) and 1/4 (HFP 1.5 or later) are
- supported, otherwise Excluded.
-C.2: Mandatory if 1/1 (A2DP 1.2 or later) is supported, otherwise Excluded.
+C.1: Mandatory if TSPC_MPS_1_1 and TSPC_MPS_1_4 are supported, otherwise
+ Excluded.
+C.2: Mandatory if TSPC_MPS_1_1 is supported, otherwise Excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-opp.txt b/android/pics-opp.txt
index 4284da69..145198d4 100644..100755
--- a/android/pics-opp.txt
+++ b/android/pics-opp.txt
@@ -1,6 +1,6 @@
OPP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-pan.txt b/android/pics-pan.txt
index 73461f54..57863c05 100644..100755
--- a/android/pics-pan.txt
+++ b/android/pics-pan.txt
@@ -1,6 +1,6 @@
PAN PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
diff --git a/android/pics-pbap.txt b/android/pics-pbap.txt
index afd100b0..bc01d8a4 100644..100755
--- a/android/pics-pbap.txt
+++ b/android/pics-pbap.txt
@@ -1,6 +1,6 @@
PBAP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -158,10 +158,10 @@ TSPC_PBAP_7_11 False PCE: Single Response Mode (C.1)
TSPC_PBAP_7_12 False PCE: Single Response Mode Parameter
(ability to parse) (C.1)
TSPC_PBAP_7_13 False PCE: Single Response Mode Parameter
- (ability to send) (C.1)
+ (ability to send) (C.2)
-------------------------------------------------------------------------------
C.1: Mandatory if TSPC_PBAP_0_3 (PBAP 1.2) is supported, otherwise Excluded.
-C.2: Optional if TSPC_PBAP_0_3 (PBAP 1.2) is supported, otherwise Excluded.
+C.2: Optional if TSPC_PBAP_2a_3 (PBAP 1.2) is supported, otherwise Excluded.
-------------------------------------------------------------------------------
@@ -322,7 +322,7 @@ TSPC_PBAP_14_13 False PSE: Single Response Mode Parameter
(ability to send) (C.2)
-------------------------------------------------------------------------------
C.1: Mandatory if TSPC_PBAP_0_3 (PBAP 1.2) is supported, otherwise Excluded.
-C.2: Optional if TSPC_PBAP_0_3 (PBAP 1.2) is supported, otherwise Excluded.
+C.2: Optional if TSPC_PBAP_9a_3 (PBAP 1.2) is supported, otherwise Excluded.
-------------------------------------------------------------------------------
diff --git a/android/pics-rfcomm.txt b/android/pics-rfcomm.txt
index 384f81db..032ee738 100644..100755
--- a/android/pics-rfcomm.txt
+++ b/android/pics-rfcomm.txt
@@ -1,6 +1,6 @@
RFCOMM PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -25,7 +25,7 @@ Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_RFCOMM_1_1 True (*) Initialize RFCOMM Session (C.2)
TSPC_RFCOMM_1_2 True (*) Respond to Initialization of an RFCOMM
- Session (C.2)
+ Session (C.1)
TSPC_RFCOMM_1_3 True Shutdown RFCOMM Session (M)
TSPC_RFCOMM_1_4 True Respond to a Shutdown of an RFCOMM
Session (M)
@@ -49,13 +49,11 @@ TSPC_RFCOMM_1_20 True (*) Send RPN Command (O)
TSPC_RFCOMM_1_21 True (*) Closing Multiplexer by First Sending
a DISC Command (O)
TSPC_RFCOMM_1_22 True Support of Credit Based Flow Control (M)
-TSPC_RFCOMM_1_23 True (*) IUT Responds to Establishment of
- a DLC (C.1)
-------------------------------------------------------------------------------
C.1: Mandatory if SPP 1/2 (Device B) is supported, otherwise Excluded.
C.2: Mandatory if SPP 1/1 (Device A) is supported, otherwise Excluded.
C.3: Mandatory if SPP 1/1 (Device A) is supported, otherwise Optional.
-C.4: Mandatory to support if 0/2 (RFCOMM 1.2) is supported, otherwise Optional.
+C.4: Mandatory to support if TSPC_RFCOMM_0_2 is supported, otherwise Optional.
-------------------------------------------------------------------------------
diff --git a/android/pics-scpp.txt b/android/pics-scpp.txt
index 6e4f599a..601ac32a 100644..100755
--- a/android/pics-scpp.txt
+++ b/android/pics-scpp.txt
@@ -1,6 +1,6 @@
ScPP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
@@ -14,7 +14,7 @@ Parameter Name Selected Description
TSPC_ScPP_1_1 False (*) Scan Server (C.1)
TSPC_ScPP_1_2 True Scan Client (C.1)
-------------------------------------------------------------------------------
-Note: C.1 is not explained in the spec for ScPP.
+Note: Mandatory to support at least one of TSPC_ScPP_1_1 or TSPC_ScPP_1_2.
-------------------------------------------------------------------------------
diff --git a/android/pics-sdp.txt b/android/pics-sdp.txt
index 9aae1904..508b80dd 100644..100755
--- a/android/pics-sdp.txt
+++ b/android/pics-sdp.txt
@@ -1,6 +1,6 @@
SDP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -41,8 +41,8 @@ TSPC_SDP_2_2 True (*) Support for respond on search of Service,
TSPC_SDP_2_3 True (*) Search for services using the continuation
state (C.1)
-------------------------------------------------------------------------------
-C.1 Mandatory to support if the client role is supported (1b/2)
-C.2 Mandatory to support if the server role is supported (1b/1)
+C.1 Mandatory to support if the client role is supported TSPC_SDP_1b_2
+C.2 Mandatory to support if the server role is supported TSPC_SDP_1b_1
-------------------------------------------------------------------------------
@@ -136,5 +136,5 @@ TSPC_SDP_9_17 True (*) AdditionalProtocolDescriptorList (C.1)
TSPC_SDP_9_18 True ServiceRecordHandle (M)
TSPC_SDP_9_19 True ServiceClassIDList (M)
-------------------------------------------------------------------------------
-C.1: Optional if 9/2 is supported, otherwise excluded
+C.1: Optional if TSPC_SDP_9_2 is supported, otherwise excluded
-------------------------------------------------------------------------------
diff --git a/android/pics-sm.txt b/android/pics-sm.txt
index c5caec63..c31fe76a 100644..100755
--- a/android/pics-sm.txt
+++ b/android/pics-sm.txt
@@ -1,8 +1,9 @@
SM PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
+^ - field not available on PTS
M - mandatory
O - optional
@@ -12,9 +13,11 @@ O - optional
Parameter Name Selected Description
-------------------------------------------------------------------------------
TSPC_SM_1_1 True Master Role (Initiator) (C.1)
-TSPC_SM_1_2 True Slave Role (Responder) (C.1)
+TSPC_SM_1_2 True Slave Role (Responder) (C.2)
-------------------------------------------------------------------------------
-C.1: At least one of these features shall be supported.
+C.1: Mandatory to support if TSPC_SM_1_2 is NOT supported, otherwise Optional
+C.2: Optional IF ((4.0 OR 4.0+HS) AND TSPC_GAP_5_3) OR ((4.1 OR 4.1+HS OR 4.2
+ OR 4.2+HS) AND (TSPC_GAP_5_3 OR TSPC_GAP_38_3)))
-------------------------------------------------------------------------------
@@ -26,8 +29,10 @@ TSPC_SM_2_1 True Authenticated MITM protection (O)
TSPC_SM_2_2 True Unauthenticated no MITM protection (C.1)
TSPC_SM_2_3 True No security requirements (M)
TSPC_SM_2_4 False (*) OOB supported (O)
+TSPC_SM_2_5 (^) LE Secure Connections (C.2)
-------------------------------------------------------------------------------
C.1: If TSPC_SM_2_1 is supported then Mandatory, else Optional
+C.2: Optional IF Core 4.2 OR Core 4.2+HS are supported, otherwise Excluded
-------------------------------------------------------------------------------
@@ -47,8 +52,8 @@ TSPC_SM_4_1 True Just Works (O)
TSPC_SM_4_2 True Passkey Entry (C.1)
TSPC_SM_4_3 False (*) Out of Band (C.1)
-------------------------------------------------------------------------------
-C.1: If TSPC_SM_2_1 is supported, at least one of these features shall be
- supported.
+C.1: Mandatory to support at least one of the defined methods IF TSPC_SM_2_1 is
+ supported, otherwise Excluded.
-------------------------------------------------------------------------------
@@ -63,7 +68,7 @@ TSPC_SM_5_4 True Slave Initiated Security – Master response(C.2)
-------------------------------------------------------------------------------
C.1: Mandatory if TSPC_SM_1_2 is supported, otherwise Excluded
C.2: Mandatory if TSPC_SM_1_1 is supported, otherwise Excluded
-C.3: Mandatory IF TSPC_SM_2_1 OR TSPC_SM_2_1 OR TSPC_SM_2_4 is supported,
+C.3: Mandatory IF TSPC_SM_2_1 OR TSPC_SM_2_2 OR TSPC_SM_2_4 is supported,
otherwise Excluded
-------------------------------------------------------------------------------
@@ -85,7 +90,7 @@ TSPC_SM_7_1 True Encryption Key (C.1)
TSPC_SM_7_2 True Identity Key (C.2)
TSPC_SM_7_3 True Signing Key (C.3)
-------------------------------------------------------------------------------
-C.1: Mandatory if GAP (24/2 OR 42/6) is supported, ELSE Optional
-C.2: Mandatory if GAP (26/3) is supported, ELSE Optional
-C.3: Mandatory if GAP (25/6 OR 35/6) is supported, ELSE Optional
+C.1: Mandatory if TSPC_GAP_24_2 OR TSPC_GAP_42_6 is supported, ELSE Optional
+C.2: Mandatory if TSPC_GAP_26_3 is supported, ELSE Optional
+C.3: Mandatory if TSPC_GAP_25_6 OR TSPC_GAP_35_6 is supported, ELSE Optional
-------------------------------------------------------------------------------
diff --git a/android/pics-spp.txt b/android/pics-spp.txt
index d9bb883a..d6bf97aa 100644..100755
--- a/android/pics-spp.txt
+++ b/android/pics-spp.txt
@@ -1,6 +1,6 @@
SPP PICS for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
# - not yet implemented/supported
@@ -80,11 +80,11 @@ TSPC_SPP_4_5 True (*) Displayable text name (C.2)
TSPC_SPP_4_6 True (*) BluetoothProfileDescriptorList (C.3)
-------------------------------------------------------------------------------
C.1: Mandatory for role B, if capability 'Support of Serial Profile Service'
- (SPP 2/1) supported. Irrelevant for role A.
-C.2: Mandatory to support if 2/1 (Support of Serial Profile Service) AND 0/1
- (SPP v1.1) are supported, otherwise Optional.
-C.3: Mandatory to support if 2/1 (Support of Serial Profile Service) AND 0/2
- (SPP v1.2) are supported, otherwise Optional.
+ (TSPC_SPP_2_1) supported. Irrelevant for role A.
+C.2: Mandatory to support if TSPC_SPP_2_1 AND TSPC_SPP_0_1 are supported,
+ otherwise Optional.
+C.3: Mandatory to support if TSPC_SPP_2_1 AND TSPC_SPP_0_2 are supported,
+ otherwise Optional.
-------------------------------------------------------------------------------
diff --git a/android/pixit-a2dp.txt b/android/pixit-a2dp.txt
index b6ef7429..c7f97629 100644..100755
--- a/android/pixit-a2dp.txt
+++ b/android/pixit-a2dp.txt
@@ -1,6 +1,6 @@
A2DP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-avctp.txt b/android/pixit-avctp.txt
index 4b2c783c..ef85510c 100644..100755
--- a/android/pixit-avctp.txt
+++ b/android/pixit-avctp.txt
@@ -1,6 +1,6 @@
AVCTP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-avdtp.txt b/android/pixit-avdtp.txt
index c4b7ed88..f73b6769 100644..100755
--- a/android/pixit-avdtp.txt
+++ b/android/pixit-avdtp.txt
@@ -1,6 +1,6 @@
AVDTP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-avrcp.txt b/android/pixit-avrcp.txt
index c4298287..9d5b87e1 100644..100755
--- a/android/pixit-avrcp.txt
+++ b/android/pixit-avrcp.txt
@@ -1,6 +1,6 @@
AVRCP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-bnep.txt b/android/pixit-bnep.txt
index 9a26cd2a..1366535a 100644..100755
--- a/android/pixit-bnep.txt
+++ b/android/pixit-bnep.txt
@@ -1,6 +1,6 @@
BNEP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-did.txt b/android/pixit-did.txt
index 295febcd..0a0f1cc3 100644..100755
--- a/android/pixit-did.txt
+++ b/android/pixit-did.txt
@@ -1,6 +1,6 @@
DID PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-dis.txt b/android/pixit-dis.txt
index 13fe78f7..e53532ea 100644..100755
--- a/android/pixit-dis.txt
+++ b/android/pixit-dis.txt
@@ -1,6 +1,6 @@
DIS PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-gap.txt b/android/pixit-gap.txt
index 7a7107c0..92a81354 100644..100755
--- a/android/pixit-gap.txt
+++ b/android/pixit-gap.txt
@@ -1,6 +1,6 @@
GAP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
@@ -11,7 +11,7 @@ PTS version: 6.0
Parameter Name Value
-------------------------------------------------------------------------------
TSPX_bd_addr_iut 112233445566 (*&)
-TSPX_bd_addr_PTS 000000000000
+TSPX_bd_addr_PTS C000DEADBEEF
TSPX_broadcaster_class_of_device 100104
TSPX_observer_class_of_device 100104
TSPX_peripheral_class_of_device 100104
@@ -36,8 +36,8 @@ TSPX_iut_privacy_enabled False
TSPX_psm 1001
TSPX_iut_valid_connection_interval_min 00C8
TSPX_iut_valid_conneciton_interval_max 0960
-TSPX_iut_valid_connection_latency 0007
-TSPX_iut_valid_timeout_multiplier 0960
+TSPX_iut_valid_connection_latency 0006
+TSPX_iut_valid_timeout_multiplier 0962
TSPX_iut_connection_parameter_timeout 30000
TSPX_iut_invalid_connection_interval_min 0000
TSPX_iut_invalid_conneciton_interval_max 0000
diff --git a/android/pixit-gatt.txt b/android/pixit-gatt.txt
index 04a5d0b3..c6cfaa7f 100644..100755
--- a/android/pixit-gatt.txt
+++ b/android/pixit-gatt.txt
@@ -1,6 +1,6 @@
GATT PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-gavdp.txt b/android/pixit-gavdp.txt
index 98e77905..0ee9eca7 100644..100755
--- a/android/pixit-gavdp.txt
+++ b/android/pixit-gavdp.txt
@@ -1,6 +1,6 @@
GAVDP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-hdp.txt b/android/pixit-hdp.txt
index ccf0cf3c..ca9b8a8b 100644..100755
--- a/android/pixit-hdp.txt
+++ b/android/pixit-hdp.txt
@@ -1,6 +1,6 @@
HDP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-hfp.txt b/android/pixit-hfp.txt
index dfae9bf9..896744e7 100644..100755
--- a/android/pixit-hfp.txt
+++ b/android/pixit-hfp.txt
@@ -1,6 +1,6 @@
HFP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-hid.txt b/android/pixit-hid.txt
index 3c93fcae..511957ba 100644..100755
--- a/android/pixit-hid.txt
+++ b/android/pixit-hid.txt
@@ -1,6 +1,6 @@
HID PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-hogp.txt b/android/pixit-hogp.txt
index e72948eb..6a38d190 100644..100755
--- a/android/pixit-hogp.txt
+++ b/android/pixit-hogp.txt
@@ -1,6 +1,6 @@
HOGP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
@@ -25,5 +25,5 @@ TSPX_input_report_data CDA6F8B3AA
TSPX_output_report_data 001234567890EF
TSPX_feature_report_data 872D3F45EA
TSPX_tester_appearance 03C0
-TSPX_iut_use_resolvable_random_address FALSE
+TSPX_iut_use_resolvable_random_address FALSE
-------------------------------------------------------------------------------
diff --git a/android/pixit-hsp.txt b/android/pixit-hsp.txt
index d7a8e3c1..9ba74d2a 100644..100755
--- a/android/pixit-hsp.txt
+++ b/android/pixit-hsp.txt
@@ -1,6 +1,6 @@
HSP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-iopt.txt b/android/pixit-iopt.txt
index 4cc6fd46..181a91da 100644..100755
--- a/android/pixit-iopt.txt
+++ b/android/pixit-iopt.txt
@@ -1,6 +1,6 @@
IOPT PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-l2cap.txt b/android/pixit-l2cap.txt
index bdd676f1..23fad191 100644..100755
--- a/android/pixit-l2cap.txt
+++ b/android/pixit-l2cap.txt
@@ -1,6 +1,6 @@
L2CAP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
@@ -19,7 +19,7 @@ TSPX_flushto FFFF
TSPX_inmtu 02A0
TSPX_no_fail_verditcs FALSE
TSPX_oumtu 02A0
-TSPX_tester_mps 0017 (*)
+TSPX_tester_mps 0017
TSPX_tester_mtu 02A0
TSPX_iut_role_initiator TRUE (*)
TSPX_le_psm 0080 (*)
@@ -46,4 +46,14 @@ TSPX_use_dynamic_pin FALSE
TSPX_iut_SDU_size_in_bytes 144
TSPX_secure_simple_pairing_pass_key_confirmation FALSE
TSPX_iut_address_type_random FALSE
+TSPX_tester_adv_interval_min 0030
+TSPX_tester_adv_interval_max 0050
+TSPX_tester_le_scan_interval 0C80
+TSPX_tester_le_scan_window 0C80
+TSPX_tester_conn_interval_min 0028
+TSPX_tester_conn_interval_max 0050
+TSPX_tester_conn_latency 0000
+TSPX_tester_supervision_timeout 0C80
+TSPX_tester_min_CE_length 0080
+TSPX_tester_max_CE_length 0C80
-------------------------------------------------------------------------------
diff --git a/android/pixit-map.txt b/android/pixit-map.txt
index a7626dd8..90272cb6 100644..100755
--- a/android/pixit-map.txt
+++ b/android/pixit-map.txt
@@ -1,6 +1,6 @@
MAP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-mcap.txt b/android/pixit-mcap.txt
index f3d33a1d..a8bbe528 100644..100755
--- a/android/pixit-mcap.txt
+++ b/android/pixit-mcap.txt
@@ -1,6 +1,6 @@
MCAP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-mps.txt b/android/pixit-mps.txt
index 86511bdf..116a8c0d 100644..100755
--- a/android/pixit-mps.txt
+++ b/android/pixit-mps.txt
@@ -1,6 +1,6 @@
MPS PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-opp.txt b/android/pixit-opp.txt
index 385cc1f0..f6651a1c 100644..100755
--- a/android/pixit-opp.txt
+++ b/android/pixit-opp.txt
@@ -1,6 +1,6 @@
OPP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-pan.txt b/android/pixit-pan.txt
index 6c00d27c..713646ef 100644..100755
--- a/android/pixit-pan.txt
+++ b/android/pixit-pan.txt
@@ -1,6 +1,6 @@
PAN PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT or PTS Bluetooth/MAC address respectively
diff --git a/android/pixit-pbap.txt b/android/pixit-pbap.txt
index 034456a7..9bf6c06d 100644..100755
--- a/android/pixit-pbap.txt
+++ b/android/pixit-pbap.txt
@@ -1,6 +1,6 @@
PBAP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
@@ -33,4 +33,5 @@ TSPX_obex_auth_password 0000
TSPX_no_confirmations False
TSPX_PSE_vCardSelector 0000000000000001
TSPX_Automation False
+TSPX_search_criteria PTS
-------------------------------------------------------------------------------
diff --git a/android/pixit-rfcomm.txt b/android/pixit-rfcomm.txt
index a3fbb270..88402a5c 100644..100755
--- a/android/pixit-rfcomm.txt
+++ b/android/pixit-rfcomm.txt
@@ -1,6 +1,6 @@
RFCOMM PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-scpp.txt b/android/pixit-scpp.txt
index 105c46a0..c8d9f372 100644..100755
--- a/android/pixit-scpp.txt
+++ b/android/pixit-scpp.txt
@@ -1,6 +1,6 @@
ScPP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-sdp.txt b/android/pixit-sdp.txt
index 2875256b..b430f843 100644..100755
--- a/android/pixit-sdp.txt
+++ b/android/pixit-sdp.txt
@@ -1,6 +1,6 @@
SDP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
@@ -30,7 +30,7 @@ TSPX_sdp_service_search_pattern_service_info_time_to_live
TSPX_sdp_service_search_pattern_version_number_list 1000(*)
TSPX_sdp_service_search_pattern_service_name
TSPX_sdp_service_search_pattern_service_record_state
-TSPX_sdp_unsupported_attribute_id
+TSPX_sdp_unsupported_attribute_id EEEE
TSPX_security_enabled FALSE
TSPX_delete_link_key FALSE
TSPX_bd_addr_iut 112233445566(*&)
diff --git a/android/pixit-sm.txt b/android/pixit-sm.txt
index 98e2ab5e..6facbb88 100644..100755
--- a/android/pixit-sm.txt
+++ b/android/pixit-sm.txt
@@ -1,6 +1,6 @@
SM PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pixit-spp.txt b/android/pixit-spp.txt
index 8e2d70f5..4bd54d0a 100644..100755
--- a/android/pixit-spp.txt
+++ b/android/pixit-spp.txt
@@ -1,6 +1,6 @@
SPP PIXIT for the PTS tool.
-PTS version: 6.0
+PTS version: 6.1
* - different than PTS defaults
& - should be set to IUT Bluetooth address
diff --git a/android/pts-a2dp.txt b/android/pts-a2dp.txt
index 500c631c..7131a739 100644..100755
--- a/android/pts-a2dp.txt
+++ b/android/pts-a2dp.txt
@@ -1,8 +1,8 @@
PTS test results for A2DP
-PTS version: 6.0
-Tested: 14-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested 21-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -15,24 +15,29 @@ N/A test is disabled due to PICS setup
Test Name Result Notes
-------------------------------------------------------------------------------
TC_SRC_CC_BV_09_I PASS Start streaming
-TC_SRC_CC_BV_10_I PASS
-TC_SRC_REL_BV_01_I PASS Connect to PTS from IUT. When requested
- disconnect from IUT
-TC_SRC_REL_BV_02_I PASS
-TC_SRC_SET_BV_01_I PASS Connect to PTS (open a2dp)
+TC_SRC_CC_BV_10_I PASS Start streaming
+TC_SRC_REL_BV_01_I PASS When requested disconnect from IUT
+TC_SRC_REL_BV_02_I PASS Start streaming
+TC_SRC_SET_BV_01_I PASS
TC_SRC_SET_BV_02_I PASS
TC_SRC_SET_BV_03_I PASS Start streaming
TC_SRC_SET_BV_04_I PASS Start streaming
-TC_SRC_SET_BV_05_I PASS IUT must be moved out of range
- JIRA issue BA-314
-TC_SRC_SET_BV_06_I PASS IUT must be moved out of range
-TC_SRC_SUS_BV_01_I PASS Stop streaming
-TC_SRC_SUS_BV_02_I PASS
+TC_SRC_SET_BV_05_I PASS Start streaming
+ IUT must be moved out of range
+ Initiate connection
+TC_SRC_SET_BV_06_I PASS PTS issue#13469
+ IUT must be moved out of range
+ To pass set TSPX_no_avrcp to TRUE
+TC_SRC_SUS_BV_01_I PASS Start streaming
+ Stop streaming
+ Start streaming
+TC_SRC_SUS_BV_02_I PASS Start streaming
TC_SRC_SDP_BV_01_I PASS
TC_SRC_AS_BV_01_I PASS Requires checking if the output on the IUT is
correct
TC_SRC_AS_BV_02_I N/A
TC_SRC_AS_BV_03_I N/A
+TC_SRC_SYN_BV_02_I N/A
-------------------------------------------------------------------------------
@@ -60,4 +65,6 @@ TC_SNK_SUS_BV_01_I N/A
TC_SNK_SUS_BV_02_I N/A
TC_SNK_SDP_BV_02_I N/A
TC_SNK_AS_BV_01_I N/A
+TC_SNK_AS_BV_02_I N/A
+TC_SNK_SYN_BV_01_I N/A
-------------------------------------------------------------------------------
diff --git a/android/pts-avctp.txt b/android/pts-avctp.txt
index d05aa05c..ec483227 100644..100755
--- a/android/pts-avctp.txt
+++ b/android/pts-avctp.txt
@@ -1,8 +1,8 @@
PTS test results for AVCTP
-PTS version: 6.0
-Tested: 11-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 21-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-avdtp.txt b/android/pts-avdtp.txt
index 683ba6d5..1a5699db 100644..100755
--- a/android/pts-avdtp.txt
+++ b/android/pts-avdtp.txt
@@ -1,8 +1,8 @@
PTS test results for AVDTP
-PTS version: 6.0
-Tested: 16-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 22-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -90,7 +90,7 @@ TC_ACP_SRC_SIG_SMG_BV_24_C PASS avdtptest -d SRC -l
TC_ACP_SRC_SIG_SMG_BV_26_C PASS avdtptest -d SRC -l
TC_ACP_SRC_SIG_SMG_BV_27_C PASS avdtptest -d SRC -l
TC_ACP_SRC_SIG_SMG_ESR05_BV_14_C N/A
-TC_ACP_SRC_SIG_SMG_BI_02_C N/A
+TC_ACP_SRC_SIG_SMG_BI_02_C PASS avdtptest -d SRC -l
TC_ACP_SRC_SIG_SMG_BI_03_C N/A
TC_ACP_SRC_SIG_SMG_BI_05_C PASS avdtptest -d SRC -l
TC_ACP_SRC_SIG_SMG_BI_06_C N/A
diff --git a/android/pts-avrcp.txt b/android/pts-avrcp.txt
index 955b37ee..b7e13868 100644..100755
--- a/android/pts-avrcp.txt
+++ b/android/pts-avrcp.txt
@@ -1,8 +1,8 @@
PTS test results for AVRCP
-PTS version: 6.0
-Tested: 21-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 21-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -16,6 +16,19 @@ Test Name Result Notes
-------------------------------------------------------------------------------
TC_CT_BGN_BV_01_I N/A
TC_CT_BGN_BV_02_I N/A
+TC_CT_CA_BV_01_C N/A
+TC_CT_CA_BV_03_C N/A
+TC_CT_CA_BV_05_C N/A
+TC_CT_CA_BV_07_C N/A
+TC_CT_CA_BV_09_C N/A
+TC_CT_CA_BV_11_C N/A
+TC_CT_CA_BV_13_C N/A
+TC_CT_CA_BV_15_C N/A
+TC_CT_CA_BV_17_C N/A
+TC_CT_CA_BV_18_C N/A
+TC_CT_CA_BV_01_I N/A
+TC_CT_CA_BV_02_I N/A
+TC_CT_CA_BV_03_I N/A
TC_CT_CEC_BV_01_I N/A
TC_CT_CEC_BV_02_I N/A
TC_CT_CFG_BV_01_C N/A
@@ -26,41 +39,44 @@ TC_CT_CRC_BV_02_I N/A
TC_CT_ICC_BV_01_I N/A
TC_CT_ICC_BV_02_I N/A
TC_CT_MCN_CB_BV_01_C N/A
+TC_CT_MCN_CB_BV_04_C N/A
+TC_CT_MCN_CB_BV_07_C N/A
+TC_CT_MCN_CB_BV_12_C N/A
TC_CT_MCN_CB_BV_01_I N/A
TC_CT_MCN_CB_BV_02_I N/A
TC_CT_MCN_CB_BV_03_I N/A
-TC_CT_MCN_CB_BV_04_C N/A
TC_CT_MCN_CB_BV_04_I N/A
TC_CT_MCN_CB_BV_05_I N/A
TC_CT_MCN_CB_BV_06_I N/A
-TC_CT_MCN_CB_BV_07_C N/A
-TC_CT_MCN_CB_BV_07_I N/A
TC_CT_MCN_NP_BV_01_C N/A
+TC_CT_MCN_NP_BV_03_C N/A
+TC_CT_MCN_NP_BV_05_C N/A
+TC_CT_MCN_NP_BV_08_C N/A
+TC_CT_MCN_NP_BV_10_C N/A
TC_CT_MCN_NP_BV_01_I N/A
TC_CT_MCN_NP_BV_02_I N/A
-TC_CT_MCN_NP_BV_03_C N/A
TC_CT_MCN_NP_BV_03_I N/A
TC_CT_MCN_NP_BV_04_I N/A
-TC_CT_MCN_NP_BV_05_C N/A
TC_CT_MCN_NP_BV_05_I N/A
TC_CT_MCN_NP_BV_06_I N/A
TC_CT_MCN_NP_BV_07_I N/A
-TC_CT_MCN_NP_BV_08_C N/A
TC_CT_MCN_SRC_BV_01_C N/A
+TC_CT_MCN_SRC_BV_03_C N/A
+TC_CT_MCN_SRC_BV_05_C N/A
+TC_CT_MCN_SRC_BV_07_C N/A
TC_CT_MCN_SRC_BV_01_I N/A
TC_CT_MCN_SRC_BV_02_I N/A
-TC_CT_MCN_SRC_BV_03_C N/A
TC_CT_MCN_SRC_BV_03_I N/A
TC_CT_MCN_SRC_BV_04_I N/A
-TC_CT_MCN_SRC_BV_05_C N/A
TC_CT_MDI_BV_01_C N/A
TC_CT_MDI_BV_03_C N/A
TC_CT_MPS_BV_01_C N/A
+TC_CT_MPS_BV_03_C N/A
+TC_CT_MPS_BV_08_C N/A
+TC_CT_MPS_BV_11_C N/A
TC_CT_MPS_BV_01_I N/A
TC_CT_MPS_BV_02_I N/A
-TC_CT_MPS_BV_03_C N/A
TC_CT_MPS_BV_03_I N/A
-TC_CT_MPS_BV_08_C N/A
TC_CT_NFY_BV_01_C N/A
TC_CT_PAS_BV_01_C N/A
TC_CT_PAS_BV_03_C N/A
@@ -97,6 +113,27 @@ Test Name Result Notes
-------------------------------------------------------------------------------
TC_TG_BGN_BV_01_I N/A
TC_TG_BGN_BV_02_I N/A
+TC_TG_CA_BI_01_C N/A
+TC_TG_CA_BI_02_C N/A
+TC_TG_CA_BI_03_C N/A
+TC_TG_CA_BI_04_C N/A
+TC_TG_CA_BI_05_C N/A
+TC_TG_CA_BI_06_C N/A
+TC_TG_CA_BI_07_C N/A
+TC_TG_CA_BI_08_C N/A
+TC_TG_CA_BI_09_C N/A
+TC_TG_CA_BI_10_C N/A
+TC_TG_CA_BV_02_C N/A
+TC_TG_CA_BV_04_C N/A
+TC_TG_CA_BV_06_C N/A
+TC_TG_CA_BV_08_C N/A
+TC_TG_CA_BV_10_C N/A
+TC_TG_CA_BV_12_C N/A
+TC_TG_CA_BV_14_C N/A
+TC_TG_CA_BV_16_C N/A
+TC_TG_CA_BV_01_I N/A
+TC_TG_CA_BV_02_I N/A
+TC_TG_CA_BV_03_I N/A
TC_TG_CEC_BV_01_I PASS
TC_TG_CEC_BV_02_I PASS
TC_TG_CFG_BI_01_C PASS
@@ -115,7 +152,6 @@ TC_TG_MCN_CB_BI_02_C N/A
TC_TG_MCN_CB_BI_03_C N/A
TC_TG_MCN_CB_BI_04_C N/A
TC_TG_MCN_CB_BI_05_C N/A
-TC_TG_MCN_CB_BV_01_I N/A
TC_TG_MCN_CB_BV_02_C N/A
TC_TG_MCN_CB_BV_02_I N/A
TC_TG_MCN_CB_BV_03_C N/A
@@ -130,6 +166,7 @@ TC_TG_MCN_CB_BV_08_C N/A
TC_TG_MCN_CB_BV_09_C N/A
TC_TG_MCN_CB_BV_10_C N/A
TC_TG_MCN_CB_BV_11_C N/A
+TC_TG_MCN_CB_BV_13_C N/A
TC_TG_MCN_NP_BI_01_C N/A
TC_TG_MCN_NP_BI_02_C N/A
TC_TG_MCN_NP_BV_01_I N/A
@@ -144,6 +181,7 @@ TC_TG_MCN_NP_BV_06_I N/A
TC_TG_MCN_NP_BV_07_C N/A
TC_TG_MCN_NP_BV_07_I N/A
TC_TG_MCN_NP_BV_09_C N/A
+TC_TG_MCN_NP_BV_11_C N/A
TC_TG_MCN_SRC_BV_01_I N/A
TC_TG_MCN_SRC_BV_02_C N/A
TC_TG_MCN_SRC_BV_02_I N/A
@@ -151,6 +189,7 @@ TC_TG_MCN_SRC_BV_03_I N/A
TC_TG_MCN_SRC_BV_04_C N/A
TC_TG_MCN_SRC_BV_04_I N/A
TC_TG_MCN_SRC_BV_06_C N/A
+TC_TG_MCN_SRC_BV_08_C N/A
TC_TG_MDI_BV_02_C PASS
TC_TG_MDI_BV_04_C PASS
TC_TG_MDI_BV_05_C PASS
@@ -166,6 +205,7 @@ TC_TG_MPS_BV_06_C N/A
TC_TG_MPS_BV_07_C N/A
TC_TG_MPS_BV_09_C N/A
TC_TG_MPS_BV_10_C N/A
+TC_TG_MPS_BV_12_C N/A
TC_TG_NFY_BI_01_C PASS
TC_TG_NFY_BV_02_C PASS Change track when requested
TC_TG_NFY_BV_03_C N/A
diff --git a/android/pts-bnep.txt b/android/pts-bnep.txt
index 91ef1c5e..8b6986a0 100644..100755
--- a/android/pts-bnep.txt
+++ b/android/pts-bnep.txt
@@ -1,9 +1,9 @@
PTS test results for BNEP
-PTS version: 6.0
-Tested: 12-March-2015
-Android version: 5.0
-Kernel version: 3.20
+PTS version: 6.1
+Tested: 11-May-2015
+Android version: 5.1
+Kernel version: 4.1
Results:
PASS test passed
@@ -33,12 +33,15 @@ TC_CTRL_BV_09_C PASS bneptest -c <PTS addr> -b <bridge> -n <iface>
-j ff:ff:ff:ff:ff:ff -y 1
TC_CTRL_BV_10_C PASS PTS issue #13169
bneptest -s -b <bridge> -n <iface>
-TC_CTRL_BV_19_C INC JIRA #BA-343
+TC_CTRL_BV_19_C PASS bneptest -s -b <bridge> -n <iface>
+TC_RX_TYPE_0_BV_11_C PASS PTS issue #13171
+ bneptest -s -b <bridge> -n <iface>
+TC_RX_C_BV_12_C PASS PTS issue #13171
+ bneptest -s -b <bridge> -n <iface>
+TC_RX_C_S_BV_13_C PASS PTS issue #13171
+ bneptest -s -b <bridge> -n <iface>
+TC_RX_C_S_BV_14_C PASS PTS issue #13171
bneptest -s -b <bridge> -n <iface>
-TC_RX_TYPE_0_BV_11_C PASS bneptest -s -b <bridge> -n <iface>
-TC_RX_C_BV_12_C PASS bneptest -s -b <bridge> -n <iface>
-TC_RX_C_S_BV_13_C PASS bneptest -s -b <bridge> -n <iface>
-TC_RX_C_S_BV_14_C PASS bneptest -s -b <bridge> -n <iface>
TC_RX_TYPE_0_BV_15_C PASS PTS issue #13169
bneptest -s -b <bridge> -n <iface>
TC_RX_TYPE_0_BV_16_C PASS PTS issue #13171
diff --git a/android/pts-did.txt b/android/pts-did.txt
index 8fd434dc..f44bf8f7 100644..100755
--- a/android/pts-did.txt
+++ b/android/pts-did.txt
@@ -1,8 +1,8 @@
PTS test results for DID
-PTS version: 6.0
-Tested: 22-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 04-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-dis.txt b/android/pts-dis.txt
index 857a149f..c7900fde 100644..100755
--- a/android/pts-dis.txt
+++ b/android/pts-dis.txt
@@ -1,8 +1,8 @@
PTS test results for DIS
-PTS version: 6.0
-Tested: 22-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 11-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-gap.txt b/android/pts-gap.txt
index 9c8be0ff..fe42d86e 100644..100755
--- a/android/pts-gap.txt
+++ b/android/pts-gap.txt
@@ -1,9 +1,9 @@
PTS test results for GAP
-PTS version: 6.0
-Tested: 19-January-2015
-Android version: 5.0
-Kernel version: 3.18
+PTS version: 6.1
+Tested: 11-May-2015
+Android version: 5.1
+Kernel version: 4.1
Results:
PASS test passed
@@ -154,10 +154,12 @@ TC_CONN_TERM_BV_01_C PASS gattc register_client
TC_CONN_PRDA_BV_01_C PASS gattc register_client
gattc listen
gattc disconnect
-TC_CONN_PRDA_BV_02_C INC PTS issue #12950
+TC_CONN_PRDA_BV_02_C PASS PTS issue #12950
gattc register_client
- bluetooth create_bond
- gattc connect
+ gattc connect <pts_bdaddr>
+ bluetooth create_bond <pts_bdaddr>
+ gattc connect <pts_bdaddr>
+ gattc test_command 226 <pts_bdaddr> 0 2
TC_BOND_NBON_BV_01_C PASS haltest:
gattc register_client
gattc connect
@@ -263,13 +265,13 @@ TC_SEC_AUT_BV_23_C PASS haltest: gattc register_client
gatts send_response 3 1 0 1d 0 0x1234
TC_SEC_AUT_BV_24_C PASS haltest: gatts register_server
gatts add_service 1 <uuid> 3
- gatts add_characteristic 1 1b <uuid> 10 34
- gatts start_service 1 1b 1
+ gatts add_characteristic 1 1d <uuid> 10 34
+ gatts start_service 1 1d 1
gatts connect
gatts disconnect
gatts connect
PTS asks for handle with insufficient encryption
- gatts send_response 2 1 0 1d 0 0x1234
+ gatts send_response 2 1 0 1f 0 0x1234
TC_SEC_CSIGN_BV_01_C PASS haltest:
gattc connect
bluetooth create_bond
@@ -279,15 +281,15 @@ TC_SEC_CSIGN_BV_01_C PASS haltest:
TC_SEC_CSIGN_BV_02_C PASS haltest: gattc register_client
gatts register_server
gatts add_service 2 <uuid> 3
- gatts add_characteristic 2 1b <uuid> 66 129
- gatts start_service 2 1b 1
+ gatts add_characteristic 2 1d <uuid> 66 129
+ gatts start_service 2 1d 1
gattc listen 1
gatts disconnect
TC_SEC_CSIGN_BI_01_C PASS gattc register_client
gatts register_server
gatts add_service 2 <uuid> 3
- gatts add_characteristic 2 1b <uuid> 66 129
- gatts start_service 2 1b 1
+ gatts add_characteristic 2 1d <uuid> 66 129
+ gatts start_service 2 1d 1
gattc listen 1
gatts disconnect
gattc disconnect
@@ -375,15 +377,15 @@ TC_DM_CON_BV_01_C PASS bluetooth set_adapter_property
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
gattc register_client
gattc listen 1
-TC_DM_NBON_BV_01_C PASS btmgmt bondable off
-TC_DM_BON_BV_01_C PASS haltest:
- create_bond and remove_bond when requested
+TC_DM_NBON_BV_01_C PASS btmgmt pairable off
+ btmgmt pair -c 0x04 -t 0x01 <addr>
+TC_DM_BON_BV_01_C PASS btmgmt pairable on
+ btmgmt pair -c 0x04 -t 0x01 <addr>
TC_DM_GIN_BV_01_C PASS
TC_DM_LIN_BV_01_C PASS
-TC_DM_NAD_BV_01_C PASS Start discovery from IUT
+TC_DM_NAD_BV_01_C PASS btmgmt find
TC_DM_NAD_BV_02_C PASS
-TC_DM_LEP_BV_01_C PASS PTS issue #12949
- bluetooth set_adapter_property
+TC_DM_LEP_BV_01_C PASS bluetooth set_adapter_property
BT_PROPERTY_ADAPTER_SCAN_MODE
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
gattc register_client
@@ -391,18 +393,18 @@ TC_DM_LEP_BV_01_C PASS PTS issue #12949
TC_DM_LEP_BV_02_C PASS Use basic rate PTS dongle
haltest:
bluetooth set_adapter_property
-TC_DM_LEP_BV_04_C PASS l2test -n <PTS bdaddr>
-TC_DM_LEP_BV_05_C PASS btmgmt find -b
+TC_DM_LEP_BV_04_C PASS haltest:
+ gattc connect <PTS bdaddr>
+TC_DM_LEP_BV_05_C PASS Use basic rate PTS dongle
+ btmgmt find -b
l2test -n <PTS bdaddr>
TC_DM_LEP_BV_06_C PASS gattc connect
-TC_DM_LEP_BV_07_C PASS PTS issue #12949
- bluetooth set_adapter_property
+TC_DM_LEP_BV_07_C PASS bluetooth set_adapter_property
BT_PROPERTY_ADAPTER_SCAN_MODE
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
gattc register_client
gattc listen 1 1
-TC_DM_LEP_BV_08_C PASS PTS issue #12949
- bluetooth set_adapter_property
+TC_DM_LEP_BV_08_C PASS bluetooth set_adapter_property
BT_PROPERTY_ADAPTER_SCAN_MODE
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
gattc register_client
@@ -413,19 +415,11 @@ TC_DM_LEP_BV_09_C PASS haltest:
BT_PROPERTY_ADAPTER_SCAN_MODE
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
gattc register_client
- bluetooth start_discovery
- gattc connect
+ gattc scan 1
+ gattc connect <PTS addr>
l2test -n -P 31 <PTS addr>
disconnect
-TC_DM_LEP_BV_10_C PASS PTS issue #12949
- haltest:
- bluetooth enable
- bluetooth set_adapter_property
- BT_PROPERTY_ADAPTER_SCAN_MODE
- BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
- gattc register_client
- gattc listen
- bluetooth start_discovery
+TC_DM_LEP_BV_10_C PASS btmgmt find
l2test -n -P 31 <PTS addr>
TC_DM_LEP_BV_11_C PASS haltest:
bluetooth enable
diff --git a/android/pts-gatt.txt b/android/pts-gatt.txt
index cbb5cee8..3531ccae 100644..100755
--- a/android/pts-gatt.txt
+++ b/android/pts-gatt.txt
@@ -1,8 +1,8 @@
PTS test results for GATT
-PTS version: 6.0
-Tested: 02-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 24-April-2015
+Android version: 5.1
Results:
PASS test passed
@@ -15,8 +15,8 @@ Test Name Result Notes
-------------------------------------------------------------------------------
TC_GAC_CL_BV_01_C PASS haltest:
gattc scan
- gattc search_service
- gattc get_characteristic
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc_uuid>
gattc write_characteristic: type 3
TC_GAC_SR_BV_01_C PASS PTS issue #13073
TSE #6271
@@ -32,66 +32,64 @@ TC_GAC_SR_BV_01_C PASS PTS issue #13073
<data> value greater than MTU
repeat with correct offset
TC_GAD_CL_BV_01_C PASS haltest:
- gattc register_client
- gattc scan
- gattc connect
- gattc search_service
- gattc disconnect
- gattc connect
- gattc refresh - NOTE: refresh should be called
- otherwise services are being read from the cache
+ NOTE: Repeat following steps if asked
+ gattc connect <client_id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc disconnect <client_if> <PTS bdaddr>
+ <conn_id>
TC_GAD_CL_BV_02_C PASS haltest:
- gattc register_client
- gattc scan
- gattc connect
- gattc search_service with given uuid
- gattc disconnect
- gattc connect
- gattc refresh
+ NOTE: Repeat following steps if asked
+ gattc connect <client_id> <PTS addr>
+ gattc search_service <conn_id> <uuid>
+ gattc disconnect <client_if> <PTS bdaddr>
+ <conn_id>
TC_GAD_CL_BV_03_C PASS haltest:
- gattc register_client
- gattc scan
- gattc connect
- gattc search_service
- gattc get_included_service
- gattc_disconnect
- gattc connect
- gattc refresh
+ NOTE: Repeat following steps if asked
+ gattc connect <client_id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x2802 0x08
+ 0x0001 0xffff
+ NOTE: Keep on mind MTU size
+ (some att rsp could not fit)
+ gattc_disconnect <client_if> <PTS bdaddr>
+ <conn_id>
TC_GAD_CL_BV_04_C PASS haltest:
- when requested: gattc get_characteristic
+ NOTE: Repeat following steps if asked
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
TC_GAD_CL_BV_05_C PASS haltest:
- when requested: gattc get_characteristic
- handle: check from btmon logs
+ NOTE: Repeat following steps if asked
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x2803 0x08
+ <start hdl> <end hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAD_CL_BV_06_C PASS haltest:
- when requested: gattc get_descriptor
-TC_GAD_CL_BV_07_C PASS bluetooth get_remote_services
-TC_GAD_CL_BV_08_C PASS bluetooth get_remote_services
+ NOTE: Repeat following steps if asked
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <conn_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
+TC_GAD_CL_BV_07_C PASS haltest:
+ NOTE: Repeat following step if asked
+ bluetooth get_remote_services
+TC_GAD_CL_BV_08_C PASS haltest:
+ NOTE: Repear following step if asked
+ bluetooth get_remote_services
TC_GAD_SR_BV_01_C PASS haltest:
gattc register_client
gattc listen
- gatts register_server
- gatts add_service
- gatts add_characteristic
- gatts start_service
- gatts add_service
- gatts add_included_service
- gatts start_service
TC_GAD_SR_BV_02_C PASS haltest:
gattc register_client
gattc listen
- gatts register_server
- gatts add_service
- gatts add_characteristic
- gatts start_service
- gatts add_service
- gatts add_included_service
- gatts start_service
TC_GAD_SR_BV_03_C PASS haltest:
gattc register_client
gattc listen
gatts register_server
gatts add_service
- gatts add_characteristic
gatts start_service
gatts add_service
gatts add_included_service
@@ -99,33 +97,12 @@ TC_GAD_SR_BV_03_C PASS haltest:
TC_GAD_SR_BV_04_C PASS haltest:
gattc register_client
gattc listen
- gatts register_server
- gatts add_service
- gatts add_characteristic
- gatts start_service
- gatts add_service
- gatts add_included_service
- gatts start_service
TC_GAD_SR_BV_05_C PASS haltest:
gattc register_client
gattc listen
- gatts register_server
- gatts add_service
- gatts add_characteristic
- gatts start_service
- gatts add_service
- gatts add_included_service
- gatts start_service
TC_GAD_SR_BV_06_C PASS haltest:
gattc register_client
gattc listen
- gatts register_server
- gatts add_service
- gatts add_characteristic
- gatts start_service
- gatts add_service
- gatts add_included_service
- gatts start_service
TC_GAD_SR_BV_07_C PASS haltest:
when requested:
bluetooth get_remote_services
@@ -135,66 +112,137 @@ TC_GAD_SR_BV_08_C PASS haltest:
bluetooth get_remote_services
NOTE: check if found requested service
TC_GAR_CL_BV_01_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_01_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0a <invalid char hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_02_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_03_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0a <inf. auth. att hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_04_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0a <inf. auth. att hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_05_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc read_characteristic
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BV_03_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 0x0001 0xffff
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_06_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_07_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_09_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_10_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_11_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BV_04_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ NOTE: Repeat following steps if asked
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ NOTE: After reading all characteristics
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_12_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_13_C PASS haltest:
- gattc test_command <u1> 0x0c
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0c <handle> <offset>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_14_C PASS haltest:
- gattc test_command <u1> 0x0a
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0a <char_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_15_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_16_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_17_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc read_characteristic
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BV_05_C N/A
TC_GAR_CL_BI_18_C N/A
TC_GAR_CL_BI_19_C N/A
@@ -202,52 +250,137 @@ TC_GAR_CL_BI_20_C N/A
TC_GAR_CL_BI_21_C N/A
TC_GAR_CL_BI_22_C N/A
TC_GAR_CL_BV_06_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_23_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_24_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0a <desc_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_25_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_26_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_27_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor: srvc_id based on
- handle from logs
- gattc read_descriptor
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BV_07_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ NOTE: Repeat following step if asked
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ NOTE: After reading all characteristics
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_28_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_29_C PASS haltest:
- gattc test_command <u1> 0x0c
- <u2> handle <u3>offset
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0c <handle> <offset>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_30_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> 0x0000
+ 0x0a <desc_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_31_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_32_C PASS haltest:
- gattc read_descriptor
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_33_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor: srvc_id based on
- handle from logs
- gattc read_descriptor
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc read_descriptor <client_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_CL_BI_34_C PASS haltest:
gattc connect
gattc test_command 224 <addr> 0 0x0a <handle>
gattc disconnect
TC_GAR_CL_BI_35_C PASS haltest:
- gattc read_characteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <client_id> <svc_id>
+ <char_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAR_SR_BV_01_C PASS
TC_GAR_SR_BI_01_C PASS
TC_GAR_SR_BI_02_C PASS
@@ -462,275 +595,328 @@ TC_GAR_SR_BI_35_C PASS haltest:
gatts start_service
gatts send_response <status> 0x80-0x9F
TC_GAW_CL_BV_01_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 1 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BV_02_C PASS haltest:
- gattc connect
- bluetooth create_bond
- gattc disconnect
- gattc connect
- gattc search_service
- gattc get_characteristics
- gattc write_characteristics: <type> 4
- gattc disconnect
-
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 4 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BV_03_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_02_C PASS haltest:
- gattc connect
- test_command: <cmd> 225 [u1] 18
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x12
+ <char_hdl> <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_03_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_04_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_05_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_06_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BV_05_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc execute_write <conn_id> 1
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_07_C PASS haltest:
- gattc connect
- test_command: <cmd> 225 [u1] 22
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x12
+ <char_hdl> <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_08_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc execute_write <conn_id> 1
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_09_C PASS haltest:
- gattc connect
- gattc search_service
- gattc test_command <u1> 0x16 <u2> handle
- <u3> offset <u4> data
- gattc test_command <u1> 0x18 <u2> 1
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x16
+ <char_hdl> <offset> <data>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x18 1
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_11_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_12_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_13_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BV_06_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 3
- gattc execute_write 1
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc execute_write <conn_id> 1
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_14_C PASS haltest:
- gattc connect
- test_command: <cmd> 225 [u1] 22
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x16
+ <char_hdl> <offset> <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_15_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_17_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_18_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_19_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 3 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BV_08_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <short_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_20_C PASS haltest:
- gattc connect
- test_command: <cmd> 225 [u1] 18
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x12
+ <char_hdl> <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_21_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <short_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_22_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <short_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_23_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <short_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_24_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <short_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BV_09_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 3 <data>
+ gattc execute_write <conn_id> 1
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_25_C PASS haltest:
- gattc connect
- test_command: <cmd> 225 [u1] 22
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x16
+ <char_hdl> <offset> <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_26_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 3 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_27_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x16
+ <char_hdl> <offset> <data>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x18 1
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_29_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 3 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_30_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 3 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_31_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x16
+ <desc_hdl> 0x0000 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_32_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 3 <value>
- gattc execute_write
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x16
+ <desc_hdl> <offset> <data>
+ gattc test_command 0xe1 <PTS addr> 0x0000 0x18 0
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_33_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_34_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characteristic 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_35_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_CL_BI_36_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <long_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 <data>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAW_SR_BV_01_C PASS haltest:
gatts add_service
gatts add_characteristic:
@@ -1029,18 +1215,21 @@ TC_GAW_SR_BI_35_C PASS haltest:
repeat with correct offset
gatts send_response: <status> 13
TC_GAN_CL_BV_01_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <hex_value> 0100
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 0x0100
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAN_SR_BV_01_C PASS haltest:
gatts add_service
gatts add_chaaracteristic:
<properties> 26 <permissions> 17
gatts add_descriptor: <uuid> 2902
+ <permission> 11
gatts start_service
gatts send_response
gatts send_response
@@ -1048,13 +1237,15 @@ TC_GAN_SR_BV_01_C PASS haltest:
<attr_handle> char value handle
<confirm> 0
TC_GAI_CL_BV_01_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc get_descriptor
- gattc write_descriptor 2 <hex_value> 0200
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc get_descriptor <client_id> <svc_id>
+ <char_id>
+ gattc write_descriptor <client_id> <svc_id>
+ <desc_id> 2 0x0200
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAI_SR_BV_01_C PASS haltest:
gatts add_service
gatts add_chaaracteristic:
@@ -1064,8 +1255,9 @@ TC_GAI_SR_BV_01_C PASS haltest:
gatts add_service
gatts start_service
TC_GAS_CL_BV_01_C PASS haltest:
- gattc connect
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GAS_SR_BV_01_C PASS haltest:
gatts add_service
gatts add_chaaracteristic:
@@ -1075,19 +1267,18 @@ TC_GAS_SR_BV_01_C PASS haltest:
gatts add_service
gatts start_service
TC_GAT_CL_BV_01_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc read_characcteristic
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_characteristic <conn_id> <svc_id>
+ <char_id>
wait for 30 sec timeout
TC_GAT_CL_BV_02_C PASS haltest:
- gattc connect
- gattc search_service
- gattc get_characteristic: srvc_id based on
- handle from logs
- gattc write_characcteristic 2 <short_value>
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc write_characteristic <client_id> <svc_id>
+ <char_id> 2 <value>
wait for 30 sec timeout
TC_GAT_SR_BV_01_C PASS haltest:
gatts add_service
@@ -1098,37 +1289,58 @@ TC_GAT_SR_BV_01_C PASS haltest:
gatts add_service
gatts start_service
TC_GPA_CL_BV_01_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_02_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_03_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_04_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_05_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_06_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc connect <client id> <PTS addr>
+ gattc search_service <conn_id>
+ gattc get_characteristic <conn_id> <svc uuid>
+ gattc read_descriptor <conn_id> <svc_id>
+ <char_id> <desc_id>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_07_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_08_C PASS haltest:
- gattc connect
- test_command: <cmd> 224 [u1] 8
- gattc disconnect
+ gattc connect <client id> <PTS addr>
+ gattc test_command 0xe0 <PTS addr> <char_uuid>
+ 0x08 <start_hdl> <end_hdl>
+ gattc disconnect <client_id> <PTS addr>
+ <conn_id>
TC_GPA_CL_BV_11_C PASS haltest:
gattc connect
Repeat following steps 5 times:
@@ -1191,7 +1403,8 @@ TC_GPA_SR_BV_08_C PASS haltest:
gatts add_descriptor <UUID> 2903
gatts start_service
gatts send_response
-TC_GPA_SR_BV_11_C PASS haltest:
+TC_GPA_SR_BV_11_C INC PTS issue #13392
+ haltest:
gatts add_service
gatts add_chaaracteristic:
<properties> 138 <permissions> 17
diff --git a/android/pts-gavdp.txt b/android/pts-gavdp.txt
index 4f6253d9..30b59ea3 100644..100755
--- a/android/pts-gavdp.txt
+++ b/android/pts-gavdp.txt
@@ -1,8 +1,8 @@
PTS test results for GAVDP
-PTS version: 6.0
-Tested: 20-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 08-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-hdp.txt b/android/pts-hdp.txt
index f6bf5ccb..cbe1b3a3 100644..100755
--- a/android/pts-hdp.txt
+++ b/android/pts-hdp.txt
@@ -1,8 +1,8 @@
PTS test results for HDP
-PTS version: 6.0
-Tested: 16-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 08-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-hfp.txt b/android/pts-hfp.txt
index ed17afed..05fccd88 100644..100755
--- a/android/pts-hfp.txt
+++ b/android/pts-hfp.txt
@@ -1,8 +1,8 @@
PTS test results for HFP
-PTS version: 6.0
-Tested: 16-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 14-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-hid.txt b/android/pts-hid.txt
index 79186508..80f11e84 100644..100755
--- a/android/pts-hid.txt
+++ b/android/pts-hid.txt
@@ -1,8 +1,8 @@
PTS test results for HID
-PTS version: 6.0
-Tested: 30-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 19-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -14,7 +14,6 @@ N/A test is disabled due to PICS setup
Test Name Result Notes
-------------------------------------------------------------------------------
TC_HOS_HCE_BV_01_I PASS
-TC_HOS_HCE_BV_02_I PASS
TC_HOS_HCE_BV_03_I PASS
TC_HOS_HCE_BV_04_I PASS
TC_HOS_HCR_BV_01_I PASS
diff --git a/android/pts-hogp.txt b/android/pts-hogp.txt
index 827e9b43..a6b8dc16 100644..100755
--- a/android/pts-hogp.txt
+++ b/android/pts-hogp.txt
@@ -1,8 +1,8 @@
PTS test results for HoG
-PTS version: 6.0
-Tested: 24-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 20-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -93,7 +93,7 @@ TC_HGCF_BH_BV_03_I N/A
TC_HGCF_BH_BV_04_I N/A
TC_HGCF_BH_BV_05_I N/A
TC_HGCF_BH_BV_06_I N/A
-TC_HGNF_RH_BV_01_I PASS PTS issue #12878
+TC_HGNF_RH_BV_01_I PASS
TC_HGNF_RH_BI_01_I PASS
TC_HGNF_RH_BI_01_I PASS
TC_HGNF_BH_BV_02_I N/A
diff --git a/android/pts-hsp.txt b/android/pts-hsp.txt
index 04a64133..8a48dd83 100644..100755
--- a/android/pts-hsp.txt
+++ b/android/pts-hsp.txt
@@ -1,8 +1,8 @@
PTS test results for HSP
-PTS version: 6.0
-Tested: 12-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 13-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-iopt.txt b/android/pts-iopt.txt
index 7b776a94..cd7ad32f 100644..100755
--- a/android/pts-iopt.txt
+++ b/android/pts-iopt.txt
@@ -1,8 +1,8 @@
PTS test results for IOPT
-PTS version: 6.0
-Tested: 03-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 21-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -14,7 +14,7 @@ N/A test is disabled due to PICS setup
Test Name Result Notes
-------------------------------------------------------------------------------
TC_COD_BV_01_I PASS IUT must be discoverable
-TC_COD_BV_02_I N/A
+TC_COD_BV_02_I N/A PTS issue#13473
TC_SDSS_BV_02_I PASS Note: HDP sink record should be registered before test
run, e.g. register health app via HDPSample.apk
TC_SDAS_BV_03_I PASS Note: HDP sink record should be registered before test
diff --git a/android/pts-l2cap.txt b/android/pts-l2cap.txt
index b6258615..81552dd3 100644..100755
--- a/android/pts-l2cap.txt
+++ b/android/pts-l2cap.txt
@@ -1,9 +1,9 @@
PTS test results for L2CAP
-PTS version: 6.0
-Tested: 18-December-2014
-Android version: 5.0
-Kernel version: 3.18
+PTS version: 6.1
+Tested: 28-May-2015
+Android version: 5.1
+Kernel version: 4.1
Results:
PASS test passed
@@ -19,18 +19,14 @@ Test Name Result Notes
TC_COS_CED_BV_01_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_03_C PASS l2test -y -N 1 -P 4113 <bdaddr>
TC_COS_CED_BV_04_C PASS l2test -n -P 4113 <bdaddr>
-TC_COS_CED_BV_05_C PASS PTS issue #12351
- btmgmt ssp off
- l2test -r -P 4113
+TC_COS_CED_BV_05_C PASS l2test -r -P 4113
TC_COS_CED_BV_07_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_08_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_09_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_10_C N/A
TC_COS_CED_BV_11_C PASS l2test -u -P 4113 <bdaddr>
TC_COS_CED_BI_01_C PASS
-TC_COS_CFD_BV_01_C PASS PTS issue #12351
- btmgmt ssp off
- l2test -r -P 4113
+TC_COS_CFD_BV_01_C PASS l2test -r -P 4113
TC_COS_CFD_BV_02_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_03_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_08_C PASS l2test -n -P 4113 <bdaddr>
@@ -153,32 +149,43 @@ TC_ECF_BV_05_C N/A
TC_ECF_BV_06_C N/A
TC_ECF_BV_07_C N/A
TC_ECF_BV_08_C N/A
-TC_LE_CPU_BV_01_C PASS l2test -n -V le_public -J 4
+TC_LE_CPU_BV_01_C PASS btmgmt advertising on
+ l2test -r -V le_public -J 4
TC_LE_CPU_BV_02_C PASS l2test -n -V le_public -J 4 <braddr>
TC_LE_CPU_BI_01_C PASS l2test -n -V le_public -J 4 <braddr>
-TC_LE_CPU_BI_02_C PASS l2test -r -V le_public -J 4
+TC_LE_CPU_BI_02_C PASS btmgmt advertising on
+ l2test -r -V le_public -J 4
TC_LE_REJ_BI_01_C PASS l2test -n -V le_public -J 4 <braddr>
TC_LE_REJ_BI_02_C PASS l2test -n -V le_public -J 4 <braddr>
TC_LE_CFC_BV_01_C PASS l2test -n -V le_public -P 37 <braddr>
TC_LE_CFC_BV_02_C PASS l2test -n -V le_public -P 37 <braddr>
-TC_LE_CFC_BV_03_C PASS l2test -x -N 1 -V le_public <braddr>
- Note: PIXIT TSPX_iut_role_initiator=FALSE
+TC_LE_CFC_BV_03_C PASS l2test -x -N 1 -V le_public
+ hcitool lecc <braddr>
+ hcitool ledc <handle>
TC_LE_CFC_BV_04_C PASS l2test -n -V le_public -P 241 <braddr>
TC_LE_CFC_BV_05_C PASS l2test -r -V le_public -J 4
- Note: PIXIT TSPX_iut_role_initiator=FALSE
-TC_LE_CFC_BV_06_C PASS PTS issue #12853
- Note: PIXIT TSPX_iut_role_initiator=FALSE
- l2test -x -b 1 -V le_public <braddr>
+ hcitool lecc <braddr>
+ hcitool ledc <handle>
+TC_LE_CFC_BV_06_C PASS l2test -s -N 10 -V le_public <braddr>
TC_LE_CFC_BV_07_C PASS l2test -u -V le_public <braddr>
TC_LE_CFC_BI_01_C PASS l2test -u -V le_public <bdaddr>
TC_LE_CFC_BV_08_C PASS l2test -n -V le_public -P 37 <braddr>
TC_LE_CFC_BV_09_C PASS l2test -n -V le_public -P 37 <braddr>
TC_LE_CFC_BV_16_C PASS l2test -n -V le_public -P 37 <braddr>
TC_LE_CFC_BV_17_C N/A
-TC_LE_CID_BV_01_C INC PTS issue #12730
- l2test -s -N 1 <bdaddr>
- l2test -s -N 1 -V le_public <bdaddr>
-TC_LE_CID_BV_02_I INC PTS issue #12730
- Note: PIXIT TSPX_iut_role_initiator=FALSE
- l2test -w -N 1
- l2test -w -N 1 -V le_public
+TC_LE_CID_BV_01_C PASS PTS issue #12730
+ l2test -r -J 2
+ l2test -r -J 4 -V le_public
+ hcitool cc <braddr>
+ hcitool lecc --static <braddr>
+ l2test -s -N 1 -C 0 -e 5 -D 10000 <braddr>
+ l2test -s -N 1 -C 0 -D 10000 -g 10000
+ -V le_public <braddr>
+TC_LE_CID_BV_02_I PASS PTS issue #12730
+ l2test -r -J 2
+ l2test -r -J 4 -V le_public
+ l2test -w -N 1 -C 0 -D 5000 -g 10000
+ l2test -w -N 1 -C 0 -D 5000 -e 5 -g 10000
+ -V le_public
+ hcitool cc <braddr>
+ hcitool lecc --static <braddr>
diff --git a/android/pts-map.txt b/android/pts-map.txt
index 6ca984ee..2be8db25 100644..100755
--- a/android/pts-map.txt
+++ b/android/pts-map.txt
@@ -1,8 +1,8 @@
PTS test results for MAP
-PTS version: 6.0
-Tested: 11-December-2014
-Android version: 5.0
+PTS version: 6.1
+Tested: 29-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -71,9 +71,9 @@ TC_MSE_MMB_BV_14_I PASS
TC_MSE_MMB_BV_15_I PASS
TC_MSE_MMB_BV_16_I PASS
TC_MSE_MMD_BV_02_I PASS
-TC_MSE_MMU_BV_02_I PASS At least one SMS must be present in inbox
+TC_MSE_MMU_BV_02_I PASS
TC_MSE_MMU_BV_03_I PASS
-TC_MSE_MMN_BV_02_I PASS
+TC_MSE_MMN_BV_02_I INC JIRA #BA-380
TC_MSE_MMN_BV_04_I N/A
TC_MSE_MMI_BV_02_I N/A
TC_MSE_MFB_BV_02_I N/A
@@ -83,6 +83,7 @@ TC_MSE_BC_BV_03_I N/A
TC_MSE_CON_BV_01_I N/A
TC_MSE_CON_BV_02_I N/A
TC_MSE_ROB_BV_01_I N/A
+TC_MSE_ROB_BV_02_I N/A
TC_MSE_SRM_BI_02_I N/A
TC_MSE_SRM_BI_03_I N/A
TC_MSE_SRM_BI_05_I N/A
diff --git a/android/pts-mcap.txt b/android/pts-mcap.txt
index 2ad28588..8e224a13 100644..100755
--- a/android/pts-mcap.txt
+++ b/android/pts-mcap.txt
@@ -1,8 +1,8 @@
PTS test results for MCAP
-PTS version: 6.0
-Tested: 10-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 19-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-mps.txt b/android/pts-mps.txt
index b1096e65..87a0e451 100644..100755
--- a/android/pts-mps.txt
+++ b/android/pts-mps.txt
@@ -1,8 +1,8 @@
PTS test results for MPS
-PTS version: 6.0
-Tested: 11-December-2014
-Android version: 5.0
+PTS version: 6.1
+Tested: 20-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -19,7 +19,7 @@ For full tests conformance, "Touch sounds" on IUT should be disabled
Test Name Result Notes
-------------------------------------------------------------------------------
TC_AG_PSE_HFPB_CTH_SD_BV_01_I PASS
-TC_AG_SRC_HFAV_ACT_SD_BV_01_I PASS PTS issue #13138
+TC_AG_SRC_HFAV_ACT_SD_BV_01_I PASS
TC_AG_SRC_HFAV_ACT_SD_BV_02_I PASS
TC_AG_SRC_HFAV_ACT_SD_BV_03_I PASS
TC_AG_SRC_HFAV_CLH_SD_BV_01_I PASS
@@ -27,7 +27,7 @@ TC_AG_SRC_HFAV_CLH_SD_BV_02_I N/A
TC_AG_SRC_HFAV_CLH_SD_BV_03_I PASS
TC_AG_SRC_HFAV_CLH_SD_BV_04_I PASS
TC_AG_SRC_HFAV_CLH_SD_BV_05_I PASS
-TC_AG_SRC_HFAV_CLH_SD_BV_06_I PASS PTS issue #13138
+TC_AG_SRC_HFAV_CLH_SD_BV_06_I PASS PTS issue #13466
TC_AVP_CTH_SD_BI_01_I PASS
TC_AVP_CTH_SD_BI_02_I PASS
TC_HF_SNK_HFAV_ACT_SD_BV_01_I N/A
diff --git a/android/pts-opp.txt b/android/pts-opp.txt
index 3f22a335..84967009 100644..100755
--- a/android/pts-opp.txt
+++ b/android/pts-opp.txt
@@ -1,8 +1,8 @@
PTS test results for OPP
-PTS version: 6.0
-Tested: 30-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 20-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -46,10 +46,10 @@ TC_CLIENT_OPH_BV_15_I N/A
TC_CLIENT_OPH_BV_16_I N/A
TC_CLIENT_OPH_BV_17_I N/A
TC_CLIENT_OPH_BV_18_I N/A
-TC_CLIENT_OPH_BV_19_I PASS
+TC_CLIENT_OPH_BV_19_I PASS Send file other than vCard
TC_CLIENT_OPH_BV_20_I PASS
-TC_CLIENT_OPH_BV_22_I PASS
-TC_CLIENT_OPH_BV_23_I PASS
+TC_CLIENT_OPH_BV_22_I PASS Send file greater than 2 MB
+TC_CLIENT_OPH_BV_23_I PASS Send two vCards in a single operation
TC_CLIENT_OPH_BV_24_I N/A
TC_CLIENT_OPH_BV_25_I N/A
TC_CLIENT_OPH_BV_26_I N/A
diff --git a/android/pts-pan.txt b/android/pts-pan.txt
index ba4afac2..350b84e9 100644..100755
--- a/android/pts-pan.txt
+++ b/android/pts-pan.txt
@@ -1,8 +1,8 @@
PTS test results for PAN
-PTS version: 6.0
-Tested: 17-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 11-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -11,7 +11,7 @@ INC test is inconclusive
N/A test is disabled due to PICS setup
--------------------------------------------------------------------------------
-Test Name Result Notes
+Test Name Result Notes
--------------------------------------------------------------------------------
TC_BNEP_BROADCAST_0_BV_01_C N/A
TC_BNEP_BROADCAST_0_BV_02_C N/A
@@ -39,38 +39,33 @@ TC_BNEP_FILTER_BV_14_C_TESTER_2 N/A
TC_BNEP_FILTER_BV_15_C_TESTER_1 N/A
TC_BNEP_FILTER_BV_15_C_TESTER_2 N/A
TC_BRIDGE_TX_BV_01_I PASS
-TC_BRIDGE_RX_BV_02_I PASS
- To initiate general ethernet
- use for e.g. ping.
-TC_IPv4_AUTONET_BV_01_I PASS
- To initiate general ethernet
- use for e.g. ping.
+TC_BRIDGE_RX_BV_02_I PASS To initiate general
+ ethernet use for e.g.
+ ping.
+TC_IPv4_AUTONET_BV_01_I PASS To initiate general
+ ethernet use for e.g.
+ ping.
TC_IPv6_AUTONET_BV_02_I N/A
TC_IP_DHCP_BV_03_I PASS
TC_IP_LLMNR_BV_01_I N/A
TC_IP_LLMNR_BV_02_I N/A
TC_IP_DNS_BV_01_I N/A
-TC_IP_APP_BV_03_I ip neighbour add <PTS IP addr>
- lladdr <PTS HW addr>
- dev bt-pan
- ping -c 1 <PTS IP addr>
- Note: Add ARP record if bt-pan
- connection is
- established
-TC_IP_APP_BV_05_I ip neighbour add <PTS IP addr>
- lladdr <PTS HW addr>
- dev bt-pan
- Note: Add of ARP record should
- be done immediately
- after establish of
- bt-pan, because PTS
- treat other than ICMP
- frames as error.
+TC_IP_APP_BV_03_I N/A
+TC_IP_APP_BV_05_I INC PTS issue #13436
+ ip neighbour add
+ <PTS IP addr> lladdr
+ <PTS HW addr> dev bt-pan
+ Note: ARP record should
+ be add immediately after
+ establish of bt-pan,
+ because PTS treat other
+ than ICMP frames as
+ error.
TC_MISC_ROLE_BV_01_C N/A
TC_MISC_ROLE_BV_02_C N/A
TC_MISC_UUID_BV_01_C PASS
TC_MISC_UUID_BV_02_C PASS
TC_SDP_NAP_BV_01_C PASS
TC_SDP_GN_BV_01_C N/A
-TC_SDP_PANU_BV_01_C PASS
+TC_SDP_PANU_BV_01_C N/A
--------------------------------------------------------------------------------
diff --git a/android/pts-pbap.txt b/android/pts-pbap.txt
index 89316900..0c597eb8 100644..100755
--- a/android/pts-pbap.txt
+++ b/android/pts-pbap.txt
@@ -1,8 +1,8 @@
PTS test results for PBAP
-PTS version: 6.0
-Tested: 30-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 19-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-rfcomm.txt b/android/pts-rfcomm.txt
index e9b3f26e..b1fce285 100644..100755
--- a/android/pts-rfcomm.txt
+++ b/android/pts-rfcomm.txt
@@ -1,9 +1,9 @@
PTS test results for RFCOMM
-PTS version: 6.0
-Tested: 02-February-2015
-Android version: 5.0
-Kernel version: 3.19
+PTS version: 6.1
+Tested: 12-May-2015
+Android version: 5.1
+Kernel version: 4.1
Results:
PASS test passed
@@ -32,9 +32,7 @@ TC_RFC_BV_14_C N/A
TC_RFC_BV_15_C PASS rctest -r -P 1
TC_RFC_BV_17_C PASS rctest -d -P 1
TC_RFC_BV_19_C PASS
-TC_RFC_BV_21_C PASS PTS issue #13011
- rctest -w -N 10 -P 1
-TC_RFC_BV_22_C PASS PTS issue #13011
- rctest -w -N 10 -P 1
+TC_RFC_BV_21_C PASS rctest -w -N 10 -P 1
+TC_RFC_BV_22_C PASS rctest -w -N 10 -P 1
TC_RFC_BV_25_C PASS rctest -r -P 1
-------------------------------------------------------------------------------
diff --git a/android/pts-scpp.txt b/android/pts-scpp.txt
index d747c49d..3fab984f 100644..100755
--- a/android/pts-scpp.txt
+++ b/android/pts-scpp.txt
@@ -1,8 +1,8 @@
PTS test results for ScPP
-PTS version: 6.0
-Tested: 02-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 12-May-2015
+Android version: 5.1
Results:
PASS test passed
diff --git a/android/pts-sdp.txt b/android/pts-sdp.txt
index 592306ec..8a3e8894 100644..100755
--- a/android/pts-sdp.txt
+++ b/android/pts-sdp.txt
@@ -1,8 +1,8 @@
PTS test results for SDP
-PTS version: 6.0
-Tested: 23-February-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 13-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -48,7 +48,7 @@ TC_SERVER_SA_BV_21_C PASS
TC_SERVER_SS_BI_01_C PASS
TC_SERVER_SS_BI_02_C PASS
TC_SERVER_SS_BV_01_C PASS
-TC_SERVER_SS_BV_03_C PASS PTS issue #12840
+TC_SERVER_SS_BV_03_C PASS
TC_SERVER_SS_BV_04_C PASS
TC_SERVER_SSA_BI_01_C PASS
TC_SERVER_SSA_BI_02_C PASS
diff --git a/android/pts-sm.txt b/android/pts-sm.txt
index 91737cc2..1fad3057 100644..100755
--- a/android/pts-sm.txt
+++ b/android/pts-sm.txt
@@ -1,9 +1,9 @@
PTS test results for SM
-PTS version: 6.0
-Tested: 11-February-2015
-Android version: 5.0
-kernel version: 3.20
+PTS version: 6.1
+Tested: 04-May-2015
+Android version: 5.1
+kernel version: 4.1
Results:
PASS test passed
@@ -24,12 +24,7 @@ TC_JW_BV_02_C PASS btmgmt advertising on
TC_JW_BV_05_C PASS btmgmt pair -c 0x03 -t 0x01 <addr>
TC_JW_BI_01_C PASS btmgmt pair -c 0x03 -t 0x01 <addr>
TC_JW_BI_02_C PASS btmgmt pairable on
-TC_JW_BI_03_C PASS bluetoothd is NOT running
- btmgmt power on
- btmgmt le on
- btmgmt connectable on
- btmgmt pairable on
- btmgmt discov on
+TC_JW_BI_03_C PASS btmgmt pairable on
btmgmt advertising on
TC_JW_BI_04_C PASS btmgmt pairable off
btmgmg pair -c 0x03 -t 0x01 <addr>
@@ -38,8 +33,6 @@ TC_PKE_BV_01_C PASS btmgmt pairable off
Note: provide passkey to PTS
TC_PKE_BV_02_C PASS btmgmt pairable off
btmgmt io-cap 0x04
- btmgmt advertising on
- btmgmt monitor
Note: provide passkey
TC_PKE_BV_04_C PASS btmgmt pair -c 0x04 -t 0x01 <addr>
TC_PKE_BV_05_C PASS btmgmt io-cap 0x04
@@ -50,7 +43,6 @@ TC_PKE_BI_02_C PASS btmgmt pair -c 0x04 -t 0x01 <addr>
Note: provide passkey
TC_PKE_BI_03_C PASS btmgmt io-cap 0x04
btmgmt advertising on
- btmgmt monitor
Note: Enter invalid passkey in PTS
TC_OOB_BV_01_C N/A
TC_OOB_BV_02_C N/A
@@ -59,12 +51,10 @@ TC_OOB_BV_04_C N/A
TC_OOB_BV_05_C PASS btmgmt pair -c 0x04 -t 0x01 <addr>
Note: Enter valid passkey in PTS
TC_OOB_BV_06_C PASS btmgmt advertising on
- btmgmt monitor
Note: Enter valid passkey in PTS
TC_OOB_BV_07_C PASS btmgmt pair -c 0x04 -t 0x01 <addr>
TC_OOB_BV_08_C PASS btmgmt advertising on
- btmgmt monitor
- Note: Accept pairing in btmgmt monitor
+ Note: Accept pairing in btmgmt
TC_OOB_BV_09_C N/A
TC_OOB_BV_10_C N/A
TC_OOB_BI_01_C N/A
@@ -72,10 +62,8 @@ TC_OOB_BI_02_C N/A
TC_EKS_BV_01_C PASS btmgmt pair -c 0x04 -t 0x01 <addr>
Note: Enter valid passkey in PTS
TC_EKS_BV_02_C PASS btmgmt advertising on
- btmgmt monitor
- Note: Accept pairing in btmgmt monitor
-TC_EKS_BI_01_C PASS btmgmt io-cap 0x03
- btmgmt pair -c 0x03 -t 0x01 <addr>
+ Note: Accept pairing in btmgmt
+TC_EKS_BI_01_C PASS btmgmt pair -c 0x03 -t 0x01 <addr>
TC_EKS_BI_02_C PASS btmgmt advertising on
TC_SIGN_BV_01_C INC PTS issue #12305
TC_SIGN_BV_03_C PASS haltest:
@@ -108,9 +96,7 @@ TC_KDU_BV_05_C PASS PTS issue #12302
TC_KDU_BV_06_C PASS btmgmt pair -c 0x03 -t 0x01 <addr>
TC_KDU_BV_07_C PASS btmgmt pairable on
TC_SIP_BV_01_C PASS btmgmt advertising on
- btmgmt pair -c 0x03 -t 0x01 <addr>
-TC_SIP_BV_02_C PASS btmgmt advertising off
- l2test -n -J4 -V le_public <addr>
-TC_SIE_BV_01_C PASS btmgmt advertising on
- btmgmt pair -c 0x03 -t 0x01 <addr>
+TC_SIP_BV_02_C PASS btmgmt pair -c 0x03 -t 0x01 <addr>
+TC_SIE_BV_01_C PASS btmgmt io-cap 0x03
+ btmgmt advertising on
-------------------------------------------------------------------------------
diff --git a/android/pts-spp.txt b/android/pts-spp.txt
index 2d2815b3..08458252 100644..100755
--- a/android/pts-spp.txt
+++ b/android/pts-spp.txt
@@ -1,8 +1,8 @@
PTS test results for SPP
-PTS version: 6.0
-Tested: 29-January-2015
-Android version: 5.0
+PTS version: 6.1
+Tested: 19-May-2015
+Android version: 5.1
Results:
PASS test passed
@@ -19,11 +19,4 @@ TC_DevB_APP_BV_02_C PASS haltest: socket listen BTSOCK_RFCOMM SerialPort
00001101
Note: IUT must be in connectable, discoverable
mode.
-TC_APP_BV_03_C N/A Missing in PTS
- PTS issue #12388
- Note: tests BV_03 : BV_6 currently not supported
- ETA: December 2014 (PTS 6.0)
-TC_APP_BV_04_C N/A Missing in PTS
-TC_APP_BV_05_C N/A Missing in PTS
-TC_APP_BV_06_C N/A Missing in PTS
-------------------------------------------------------------------------------
diff --git a/android/sco-ipc-api.txt b/android/sco-ipc-api.txt
index 27d5ef21..27d5ef21 100644..100755
--- a/android/sco-ipc-api.txt
+++ b/android/sco-ipc-api.txt
diff --git a/android/sco-msg.h b/android/sco-msg.h
index d1b13d70..d1b13d70 100644..100755
--- a/android/sco-msg.h
+++ b/android/sco-msg.h
diff --git a/android/sco.c b/android/sco.c
index e8ac6854..e8ac6854 100644..100755
--- a/android/sco.c
+++ b/android/sco.c
diff --git a/android/sco.h b/android/sco.h
index 4e1a2b3c..4e1a2b3c 100644..100755
--- a/android/sco.h
+++ b/android/sco.h
diff --git a/android/scpp.c b/android/scpp.c
index f8f81f37..f8f81f37 100644..100755
--- a/android/scpp.c
+++ b/android/scpp.c
diff --git a/android/scpp.h b/android/scpp.h
index 048fb9f2..048fb9f2 100644..100755
--- a/android/scpp.h
+++ b/android/scpp.h
diff --git a/android/socket-api.txt b/android/socket-api.txt
index 9f622f98..9f622f98 100644..100755
--- a/android/socket-api.txt
+++ b/android/socket-api.txt
diff --git a/android/socket.c b/android/socket.c
index 15e1bfcc..15e1bfcc 100644..100755
--- a/android/socket.c
+++ b/android/socket.c
diff --git a/android/socket.h b/android/socket.h
index b0e78c6d..b0e78c6d 100644..100755
--- a/android/socket.h
+++ b/android/socket.h
diff --git a/android/system-emulator.c b/android/system-emulator.c
index 61fb4967..61fb4967 100644..100755
--- a/android/system-emulator.c
+++ b/android/system-emulator.c
diff --git a/android/test-ipc.c b/android/test-ipc.c
index bb7d15fe..bb7d15fe 100644..100755
--- a/android/test-ipc.c
+++ b/android/test-ipc.c
diff --git a/android/tester-a2dp.c b/android/tester-a2dp.c
index f7d82c95..8397eeff 100644..100755
--- a/android/tester-a2dp.c
+++ b/android/tester-a2dp.c
@@ -236,14 +236,9 @@ struct queue *get_a2dp_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-avrcp.c b/android/tester-avrcp.c
index cec97878..737602e5 100644..100755
--- a/android/tester-avrcp.c
+++ b/android/tester-avrcp.c
@@ -584,14 +584,9 @@ struct queue *get_avrcp_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-bluetooth.c b/android/tester-bluetooth.c
index 1381f631..22077a06 100644..100755
--- a/android/tester-bluetooth.c
+++ b/android/tester-bluetooth.c
@@ -32,14 +32,14 @@ static bt_property_t prop_emu_bdaddr = {
.len = sizeof(emu_bdaddr_val),
};
-static const char emu_bdname_val[] = "BlueZ for Android";
+static char emu_bdname_val[] = "BlueZ for Android";
static bt_property_t prop_emu_bdname = {
.type = BT_PROPERTY_BDNAME,
.val = &emu_bdname_val,
.len = sizeof(emu_bdname_val) - 1,
};
-static const char emu_uuids_val[] = {
+static char emu_uuids_val[] = {
/* Multi profile UUID */
0x00, 0x00, 0x11, 0x3b, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
@@ -126,7 +126,7 @@ static struct bt_action_data prop_emu_remote_ble_rssi_req = {
.prop_type = BT_PROPERTY_REMOTE_RSSI,
};
-static const char emu_remote_bdname_val[] = "00:AA:01:01:00:00";
+static char emu_remote_bdname_val[] = "00:AA:01:01:00:00";
static bt_property_t prop_emu_remote_ble_bdname_prop = {
.type = BT_PROPERTY_BDNAME,
.val = &emu_remote_bdname_val,
@@ -188,7 +188,7 @@ static struct bt_action_data prop_emu_remote_ble_verinfo_req = {
.prop_type = BT_PROPERTY_REMOTE_VERSION_INFO,
};
-static const char prop_test_fname_val[] = "FriendlyTestName";
+static char prop_test_fname_val[] = "FriendlyTestName";
static bt_property_t prop_emu_remote_ble_fname_prop = {
.type = BT_PROPERTY_REMOTE_FRIENDLY_NAME,
.val = &prop_test_fname_val,
@@ -1224,14 +1224,9 @@ struct queue *get_bluetooth_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index b8b088be..88be3d88 100644..100755
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -3665,14 +3665,9 @@ struct queue *get_gatt_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-hdp.c b/android/tester-hdp.c
index 80f3b5f2..e8498205 100644..100755
--- a/android/tester-hdp.c
+++ b/android/tester-hdp.c
@@ -549,14 +549,9 @@ struct queue *get_hdp_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-hidhost.c b/android/tester-hidhost.c
index ab5f12bb..221b122e 100644..100755
--- a/android/tester-hidhost.c
+++ b/android/tester-hidhost.c
@@ -719,14 +719,9 @@ struct queue *get_hidhost_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-main.c b/android/tester-main.c
index 25065482..3a557923 100644..100755
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -329,7 +329,7 @@ static void mgmt_debug(const char *str, void *user_data)
static bool hciemu_post_encr_hook(const void *data, uint16_t len,
void *user_data)
{
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
/*
* Expected data: status (1 octet) + conn. handle (2 octets) +
@@ -338,6 +338,8 @@ static bool hciemu_post_encr_hook(const void *data, uint16_t len,
if (len < 4)
return true;
+ step = g_new0(struct step, 1);
+
step->callback = ((uint8_t *)data)[3] ? CB_EMU_ENCRYPTION_ENABLED :
CB_EMU_ENCRYPTION_DISABLED;
@@ -2719,8 +2721,17 @@ void emu_setup_powered_remote_action(void)
bthost_set_cmd_complete_cb(bthost, emu_connectable_complete, data);
if ((data->hciemu_type == HCIEMU_TYPE_LE) ||
- (data->hciemu_type == HCIEMU_TYPE_BREDRLE))
- bthost_set_adv_enable(bthost, 0x01, 0x02);
+ (data->hciemu_type == HCIEMU_TYPE_BREDRLE)) {
+ uint8_t adv[4];
+
+ adv[0] = 0x02; /* Field length */
+ adv[1] = 0x01; /* Flags */
+ adv[2] = 0x02; /* Flags value */
+ adv[3] = 0x00; /* Field terminator */
+
+ bthost_set_adv_data(bthost, adv, sizeof(adv));
+ bthost_set_adv_enable(bthost, 0x01);
+ }
if (data->hciemu_type != HCIEMU_TYPE_LE)
bthost_write_scan_enable(bthost, 0x03);
@@ -2952,13 +2963,15 @@ void emu_add_rfcomm_server_action(void)
struct step *current_data_step = queue_peek_head(data->steps);
struct bt_action_data *rfcomm_data = current_data_step->set_data;
struct bthost *bthost;
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
if (!rfcomm_data) {
tester_warn("Invalid l2cap_data params");
return;
}
+ step = g_new0(struct step, 1);
+
bthost = hciemu_client_get_host(data->hciemu);
bthost_add_rfcomm_server(bthost, rfcomm_data->channel,
@@ -3001,7 +3014,7 @@ void bluetooth_disable_action(void)
void bt_set_property_action(void)
{
struct test_data *data = tester_get_data();
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
struct step *current_data_step = queue_peek_head(data->steps);
bt_property_t *prop;
@@ -3011,6 +3024,8 @@ void bt_set_property_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
prop = (bt_property_t *)current_data_step->set_data;
step->action_status = data->if_bluetooth->set_adapter_property(prop);
@@ -3021,7 +3036,7 @@ void bt_set_property_action(void)
void bt_get_property_action(void)
{
struct test_data *data = tester_get_data();
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
struct step *current_data_step = queue_peek_head(data->steps);
bt_property_t *prop;
@@ -3031,6 +3046,8 @@ void bt_get_property_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
prop = (bt_property_t *)current_data_step->set_data;
step->action_status = data->if_bluetooth->get_adapter_property(
@@ -3063,7 +3080,7 @@ void bt_get_device_props_action(void)
{
struct test_data *data = tester_get_data();
struct step *current_data_step = queue_peek_head(data->steps);
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
if (!current_data_step->set_data) {
tester_debug("bdaddr not defined");
@@ -3071,6 +3088,8 @@ void bt_get_device_props_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
step->action_status =
data->if_bluetooth->get_remote_device_properties(
current_data_step->set_data);
@@ -3083,7 +3102,7 @@ void bt_get_device_prop_action(void)
struct test_data *data = tester_get_data();
struct step *current_data_step = queue_peek_head(data->steps);
struct bt_action_data *action_data = current_data_step->set_data;
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
if (!action_data) {
tester_warn("No arguments for 'get remote device prop' req.");
@@ -3091,6 +3110,8 @@ void bt_get_device_prop_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
step->action_status = data->if_bluetooth->get_remote_device_property(
action_data->addr,
action_data->prop_type);
@@ -3103,7 +3124,7 @@ void bt_set_device_prop_action(void)
struct test_data *data = tester_get_data();
struct step *current_data_step = queue_peek_head(data->steps);
struct bt_action_data *action_data = current_data_step->set_data;
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
if (!action_data) {
tester_warn("No arguments for 'set remote device prop' req.");
@@ -3111,6 +3132,8 @@ void bt_set_device_prop_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
step->action_status = data->if_bluetooth->set_remote_device_property(
action_data->addr,
action_data->prop);
@@ -3123,7 +3146,7 @@ void bt_create_bond_action(void)
struct test_data *data = tester_get_data();
struct step *current_data_step = queue_peek_head(data->steps);
struct bt_action_data *action_data = current_data_step->set_data;
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
if (!action_data || !action_data->addr) {
tester_warn("Bad arguments for 'create bond' req.");
@@ -3131,6 +3154,8 @@ void bt_create_bond_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
step->action_status =
data->if_bluetooth->create_bond(action_data->addr,
action_data->transport_type ?
@@ -3145,7 +3170,7 @@ void bt_pin_reply_accept_action(void)
struct test_data *data = tester_get_data();
struct step *current_data_step = queue_peek_head(data->steps);
struct bt_action_data *action_data = current_data_step->set_data;
- struct step *step = g_new0(struct step, 1);
+ struct step *step;
if (!action_data || !action_data->addr || !action_data->pin) {
tester_warn("Bad arguments for 'pin reply' req.");
@@ -3153,6 +3178,8 @@ void bt_pin_reply_accept_action(void)
return;
}
+ step = g_new0(struct step, 1);
+
step->action_status = data->if_bluetooth->pin_reply(action_data->addr,
TRUE,
action_data->pin_len,
diff --git a/android/tester-main.h b/android/tester-main.h
index 8a7384c5..8a7384c5 100644..100755
--- a/android/tester-main.h
+++ b/android/tester-main.h
diff --git a/android/tester-map-client.c b/android/tester-map-client.c
index 1f552a32..695c7971 100644..100755
--- a/android/tester-map-client.c
+++ b/android/tester-map-client.c
@@ -140,14 +140,9 @@ struct queue *get_map_client_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-pan.c b/android/tester-pan.c
index e033e215..9da2488a 100644..100755
--- a/android/tester-pan.c
+++ b/android/tester-pan.c
@@ -226,14 +226,9 @@ struct queue *get_pan_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/tester-socket.c b/android/tester-socket.c
index 41e14345..2264a1f1 100644..100755
--- a/android/tester-socket.c
+++ b/android/tester-socket.c
@@ -447,14 +447,9 @@ struct queue *get_socket_tests(void)
uint16_t i = 0;
list = queue_new();
- if (!list)
- return NULL;
for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
- if (!queue_push_tail(list, &test_cases[i])) {
- queue_destroy(list, NULL);
- return NULL;
- }
+ queue_push_tail(list, &test_cases[i]);
return list;
}
diff --git a/android/utils.h b/android/utils.h
index 7adc2dab..7adc2dab 100644..100755
--- a/android/utils.h
+++ b/android/utils.h
diff --git a/attrib/gatt-service.c b/attrib/gatt-service.c
index d4df218e..7b883809 100644
--- a/attrib/gatt-service.c
+++ b/attrib/gatt-service.c
@@ -631,33 +631,3 @@ fail:
g_slist_free_full(chrs, free_gatt_info);
return FALSE;
}
-
-#if 0
-guint gatt_char_value_notify(GAttrib *attrib, uint16_t handle, uint8_t *value,
- int vlen, GAttribResultFunc func, gpointer user_data)
-{
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
- guint16 plen;
-
- plen = enc_notification(handle, value, vlen, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-
-guint gatt_char_value_indicate(GAttrib *attrib, uint16_t handle, uint8_t *value,
- int vlen, GAttribResultFunc func, gpointer user_data)
-{
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
- guint16 plen;
-
- plen = enc_indication(handle, value, vlen, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-#endif
diff --git a/attrib/gatt-service.h b/attrib/gatt-service.h
index adb8ddca..a1b3fee2 100644
--- a/attrib/gatt-service.h
+++ b/attrib/gatt-service.h
@@ -85,9 +85,3 @@ bool gatt_send_noty_ind(struct btd_adapter *adapter, const bt_uuid_t *uuid,
bool gatt_send_service_changed_ind(struct btd_adapter *adapter, bt_uuid_t *uuid,
uint16_t start_handle, uint16_t end_handle);
#endif
-#if 0
-guint gatt_char_value_notify(GAttrib *attrib, uint16_t handle, uint8_t *value,
- int vlen, GAttribResultFunc func, gpointer user_data);
-guint gatt_char_value_indicate(GAttrib *attrib, uint16_t handle, uint8_t *value,
- int vlen, GAttribResultFunc func, gpointer user_data);
-#endif
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 13e5e42f..de537ad1 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -1201,23 +1201,6 @@ guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
return dd->id;
}
-#ifdef __TIZEN_PATCH__
-guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
- GAttribResultFunc func, gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- guint16 plen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
- plen = enc_find_info_req(start, end, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-#endif
-
guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
int vlen, GDestroyNotify notify, gpointer user_data)
{
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 7a0cf953..ca9650d4 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -122,8 +122,6 @@ gboolean gatt_parse_record(const sdp_record_t *rec,
uint16_t *start, uint16_t *end);
#ifdef __TIZEN_PATCH__
-guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
- GAttribResultFunc func, gpointer user_data);
guint gatt_read_char_by_offset(GAttrib *attrib, uint16_t handle, uint16_t offset,
GAttribResultFunc func, gpointer user_data);
#endif
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 2f61977c..2e1e39ac 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -95,7 +95,7 @@ static struct id_pair *store_id(GAttrib *attrib, unsigned int org_id,
return NULL;
}
-GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
+GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed)
{
gint fd;
GAttrib *attr;
@@ -111,7 +111,7 @@ GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
g_io_channel_ref(io);
attr->io = io;
- attr->att = bt_att_new(fd);
+ attr->att = bt_att_new(fd, ext_signed);
if (!attr->att)
goto fail;
@@ -220,17 +220,6 @@ struct bt_att *g_attrib_get_att(GAttrib *attrib)
return attrib->att;
}
-#ifdef __TIZEN_PATCH__
-void g_attrib_channel_unref(GAttrib *attrib)
-{
- if (attrib->io) {
- g_io_channel_shutdown(attrib->io, FALSE, NULL);
- g_io_channel_unref(attrib->io);
- attrib->io = NULL;
- }
-}
-#endif
-
gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy,
gpointer user_data)
{
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
index 55911ef4..611f9526 100644
--- a/attrib/gattrib.h
+++ b/attrib/gattrib.h
@@ -42,16 +42,13 @@ typedef void (*GAttribDebugFunc)(const char *str, gpointer user_data);
typedef void (*GAttribNotifyFunc)(const guint8 *pdu, guint16 len,
gpointer user_data);
-GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu);
+GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed);
GAttrib *g_attrib_ref(GAttrib *attrib);
void g_attrib_unref(GAttrib *attrib);
GIOChannel *g_attrib_get_channel(GAttrib *attrib);
-#ifdef __TIZEN_PATCH__
-void g_attrib_channel_unref(GAttrib *attrib);
struct bt_att *g_attrib_get_att(GAttrib *attrib);
-#endif
gboolean g_attrib_set_destroy_function(GAttrib *attrib,
GDestroyNotify destroy, gpointer user_data);
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 1a40c943..95bd20a6 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -148,7 +148,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
if (cid == ATT_CID)
mtu = ATT_DEFAULT_LE_MTU;
- attrib = g_attrib_new(io, mtu);
+ attrib = g_attrib_new(io, mtu, false);
if (opt_listen)
g_idle_add(listen_start, attrib);
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 4b421820..0880585b 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -174,7 +174,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
if (cid == ATT_CID)
mtu = ATT_DEFAULT_LE_MTU;
- attrib = g_attrib_new(iochannel, mtu);
+ attrib = g_attrib_new(iochannel, mtu, false);
g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
events_handler, attrib, NULL);
g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
diff --git a/bootstrap-configure b/bootstrap-configure
index 29cd7bf4..87766b11 100755..100644
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -12,6 +12,7 @@ fi
--sysconfdir=/etc \
--localstatedir=/var \
--enable-manpages \
+ --enable-backtrace \
--enable-experimental \
--enable-android \
--enable-sixaxis \
diff --git a/client/gatt.c b/client/gatt.c
index 11c90819..7dd3c943 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -75,12 +75,13 @@ static void print_service(GDBusProxy *proxy, const char *description)
if (!text)
text = uuid;
- rl_printf("%s%s%sService %s %s %s\n",
+ rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
description ? "[" : "",
description ? : "",
description ? "] " : "",
+ primary ? "Primary" : "Secondary",
g_dbus_proxy_get_path(proxy),
- text, primary ? "(Primary)" : "(Secondary)");
+ text);
}
void gatt_add_service(GDBusProxy *proxy)
@@ -92,7 +93,13 @@ void gatt_add_service(GDBusProxy *proxy)
void gatt_remove_service(GDBusProxy *proxy)
{
- services = g_list_remove(services, proxy);
+ GList *l;
+
+ l = g_list_find(services, proxy);
+ if (!l)
+ return;
+
+ services = g_list_delete_link(services, l);
print_service(proxy, COLORED_DEL);
}
@@ -111,7 +118,7 @@ static void print_characteristic(GDBusProxy *proxy, const char *description)
if (!text)
text = uuid;
- rl_printf("%s%s%sCharacteristic %s %s\n",
+ rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n",
description ? "[" : "",
description ? : "",
description ? "] " : "",
@@ -154,10 +161,13 @@ void gatt_add_characteristic(GDBusProxy *proxy)
void gatt_remove_characteristic(GDBusProxy *proxy)
{
- if (!characteristic_is_child(proxy))
+ GList *l;
+
+ l = g_list_find(characteristics, proxy);
+ if (!l)
return;
- characteristics = g_list_remove(characteristics, proxy);
+ characteristics = g_list_delete_link(characteristics, l);
print_characteristic(proxy, COLORED_DEL);
}
@@ -176,7 +186,7 @@ static void print_descriptor(GDBusProxy *proxy, const char *description)
if (!text)
text = uuid;
- rl_printf("%s%s%sDescriptor %s %s\n",
+ rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n",
description ? "[" : "",
description ? : "",
description ? "] " : "",
@@ -219,10 +229,13 @@ void gatt_add_descriptor(GDBusProxy *proxy)
void gatt_remove_descriptor(GDBusProxy *proxy)
{
- if (!descriptor_is_child(proxy))
+ GList *l;
+
+ l = g_list_find(descriptors, proxy);
+ if (!l)
return;
- descriptors = g_list_remove(descriptors, proxy);
+ descriptors = g_list_delete_link(descriptors, l);
print_descriptor(proxy, COLORED_DEL);
}
@@ -421,7 +434,7 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
struct iovec iov;
uint8_t value[512];
char *entry;
- int i;
+ unsigned int i;
for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
long int val;
@@ -429,17 +442,12 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
if (*entry == '\0')
continue;
-#ifndef __TIZEN_PATCH__
- if (i > 512) {
- rl_printf("Too much data\n");
- return;
- }
-#else
- if (i >= 512) {
+
+ if (i >= G_N_ELEMENTS(value)) {
rl_printf("Too much data\n");
return;
}
-#endif
+
val = strtol(entry, &endptr, 0);
if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
rl_printf("Invalid value at index %d\n", i);
diff --git a/client/main.c b/client/main.c
index 4e7a54aa..4faa9c6b 100644
--- a/client/main.c
+++ b/client/main.c
@@ -162,6 +162,7 @@ static void print_iter(const char *label, const char *name,
unsigned char byte;
const char *valstr;
DBusMessageIter subiter;
+ char *entry;
if (iter == NULL) {
rl_printf("%s%s is nil\n", label, name);
@@ -212,9 +213,14 @@ static void print_iter(const char *label, const char *name,
break;
case DBUS_TYPE_DICT_ENTRY:
dbus_message_iter_recurse(iter, &subiter);
- dbus_message_iter_get_basic(&subiter, &valstr);
+ entry = g_strconcat(name, " Key", NULL);
+ print_iter(label, entry, &subiter);
+ g_free(entry);
+
+ entry = g_strconcat(name, " Value", NULL);
dbus_message_iter_next(&subiter);
- print_iter(label, valstr, &subiter);
+ print_iter(label, entry, &subiter);
+ g_free(entry);
break;
default:
rl_printf("%s%s has unsupported type\n", label, name);
@@ -381,6 +387,8 @@ static void set_default_device(GDBusProxy *proxy, const char *attribute)
done:
rl_set_prompt(desc ? desc : PROMPT_ON);
+ printf("\r");
+ rl_on_new_line();
rl_redisplay();
g_free(desc);
}
@@ -430,12 +438,10 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
agent_unregister(dbus_conn, NULL);
}
} else if (!strcmp(interface, "org.bluez.GattService1")) {
- if (service_is_child(proxy)) {
- gatt_remove_service(proxy);
+ gatt_remove_service(proxy);
- if (default_attr == proxy)
- set_default_attribute(NULL);
- }
+ if (default_attr == proxy)
+ set_default_attribute(NULL);
} else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
gatt_remove_characteristic(proxy);
@@ -899,6 +905,222 @@ static void cmd_scan(const char *arg)
}
}
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+ DBusMessageIter value;
+ char sig[2] = { type, '\0' };
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+ dbus_message_iter_append_basic(&value, type, val);
+
+ dbus_message_iter_close_container(iter, &value);
+}
+
+static void dict_append_entry(DBusMessageIter *dict, const char *key,
+ int type, void *val)
+{
+ DBusMessageIter entry;
+
+ if (type == DBUS_TYPE_STRING) {
+ const char *str = *((const char **) val);
+
+ if (str == NULL)
+ return;
+ }
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ append_variant(&entry, type, val);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+#define DISTANCE_VAL_INVALID 0x7FFF
+
+struct set_discovery_filter_args {
+ char *transport;
+ dbus_uint16_t rssi;
+ dbus_int16_t pathloss;
+ GSList *uuids;
+};
+
+static void set_discovery_filter_setup(DBusMessageIter *iter,
+ void *user_data)
+{
+ struct set_discovery_filter_args *args = user_data;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ if (args->uuids != NULL) {
+ DBusMessageIter entry, value, arrayIter;
+ char *uuids = "UUIDs";
+ GSList *l;
+
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ /* dict key */
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+ &uuids);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ "as", &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, "s",
+ &arrayIter);
+
+ for (l = args->uuids; l != NULL; l = g_slist_next(l))
+ /* list->data contains string representation of uuid */
+ dbus_message_iter_append_basic(&arrayIter,
+ DBUS_TYPE_STRING,
+ &l->data);
+
+ dbus_message_iter_close_container(&value, &arrayIter);
+
+ /* close vararg*/
+ dbus_message_iter_close_container(&entry, &value);
+
+ /* close entry */
+ dbus_message_iter_close_container(&dict, &entry);
+ }
+
+ if (args->pathloss != DISTANCE_VAL_INVALID)
+ dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
+ &args->pathloss);
+
+ if (args->rssi != DISTANCE_VAL_INVALID)
+ dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi);
+
+ if (args->transport != NULL)
+ dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
+ &args->transport);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+
+static void set_discovery_filter_reply(DBusMessage *message,
+ void *user_data)
+{
+ DBusError error;
+
+ dbus_error_init(&error);
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("SetDiscoveryFilter failed: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ rl_printf("SetDiscoveryFilter success\n");
+}
+
+static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
+static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
+static GSList *filtered_scan_uuids;
+static char *filtered_scan_transport;
+
+static void cmd_set_scan_filter_commit(void)
+{
+ struct set_discovery_filter_args args;
+
+ args.uuids = NULL;
+ args.pathloss = filtered_scan_pathloss;
+ args.rssi = filtered_scan_rssi;
+ args.transport = filtered_scan_transport;
+ args.uuids = filtered_scan_uuids;
+
+ if (check_default_ctrl() == FALSE)
+ return;
+
+ if (g_dbus_proxy_method_call(default_ctrl, "SetDiscoveryFilter",
+ set_discovery_filter_setup, set_discovery_filter_reply,
+ &args, NULL) == FALSE) {
+ rl_printf("Failed to set discovery filter\n");
+ return;
+ }
+}
+
+static void cmd_set_scan_filter_uuids(const char *arg)
+{
+ char *uuid_str, *saveptr, *uuids, *uuidstmp;
+
+ g_slist_free_full(filtered_scan_uuids, g_free);
+ filtered_scan_uuids = NULL;
+
+ if (!arg || !strlen(arg))
+ return;
+
+ uuids = g_strdup(arg);
+ for (uuidstmp = uuids; ; uuidstmp = NULL) {
+ uuid_str = strtok_r(uuidstmp, " \t", &saveptr);
+ if (uuid_str == NULL)
+ break;
+ filtered_scan_uuids = g_slist_append(filtered_scan_uuids,
+ strdup(uuid_str));
+ }
+
+ g_free(uuids);
+
+ cmd_set_scan_filter_commit();
+}
+
+static void cmd_set_scan_filter_rssi(const char *arg)
+{
+ filtered_scan_pathloss = DISTANCE_VAL_INVALID;
+
+ if (!arg || !strlen(arg))
+ filtered_scan_rssi = DISTANCE_VAL_INVALID;
+ else
+ filtered_scan_rssi = atoi(arg);
+
+ cmd_set_scan_filter_commit();
+}
+
+static void cmd_set_scan_filter_pathloss(const char *arg)
+{
+ filtered_scan_rssi = DISTANCE_VAL_INVALID;
+
+ if (!arg || !strlen(arg))
+ filtered_scan_pathloss = DISTANCE_VAL_INVALID;
+ else
+ filtered_scan_pathloss = atoi(arg);
+
+ cmd_set_scan_filter_commit();
+}
+
+static void cmd_set_scan_filter_transport(const char *arg)
+{
+ g_free(filtered_scan_transport);
+
+ if (!arg || !strlen(arg))
+ filtered_scan_transport = NULL;
+ else
+ filtered_scan_transport = g_strdup(arg);
+
+ cmd_set_scan_filter_commit();
+}
+
+static void cmd_set_scan_filter_clear(const char *arg)
+{
+ /* set default values for all options */
+ filtered_scan_rssi = DISTANCE_VAL_INVALID;
+ filtered_scan_pathloss = DISTANCE_VAL_INVALID;
+ g_slist_free_full(filtered_scan_uuids, g_free);
+ filtered_scan_uuids = NULL;
+ g_free(filtered_scan_transport);
+ filtered_scan_transport = NULL;
+
+ cmd_set_scan_filter_commit();
+}
+
static struct GDBusProxy *find_device(const char *arg)
{
GDBusProxy *proxy;
@@ -950,8 +1172,11 @@ static void cmd_info(const char *arg)
#ifdef __TIZEN_PATCH__
print_property(proxy, "Flag");
print_property(proxy, "ManufacturerDataLen");
- print_property(proxy, "ManufacturerData");
#endif
+ print_property(proxy, "ManufacturerData");
+ print_property(proxy, "ServiceData");
+ print_property(proxy, "RSSI");
+ print_property(proxy, "TxPower");
}
static void pair_reply(DBusMessage *message, void *user_data)
@@ -1203,7 +1428,12 @@ static void cmd_disconn(const char *arg)
rl_printf("Failed to disconnect\n");
return;
}
+ if (strlen(arg) == 0) {
+ DBusMessageIter iter;
+ if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
+ dbus_message_iter_get_basic(&iter, &arg);
+ }
rl_printf("Attempting to disconnect from %s\n", arg);
}
@@ -1476,6 +1706,17 @@ static const struct {
capability_generator},
{ "default-agent",NULL, cmd_default_agent,
"Set agent as the default one" },
+ { "set-scan-filter-uuids", "[uuid1 uuid2 ...]",
+ cmd_set_scan_filter_uuids, "Set scan filter uuids" },
+ { "set-scan-filter-rssi", "[rssi]", cmd_set_scan_filter_rssi,
+ "Set scan filter rssi, and clears pathloss" },
+ { "set-scan-filter-pathloss", "[pathloss]",
+ cmd_set_scan_filter_pathloss,
+ "Set scan filter pathloss, and clears rssi" },
+ { "set-scan-filter-transport", "[transport]",
+ cmd_set_scan_filter_transport, "Set scan filter transport" },
+ { "set-scan-filter-clear", "", cmd_set_scan_filter_clear,
+ "Clears discovery filter." },
{ "scan", "<on/off>", cmd_scan, "Scan for devices" },
{ "info", "[dev]", cmd_info, "Device information",
dev_generator },
@@ -1666,7 +1907,7 @@ static guint setup_standard_input(void)
static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
- static unsigned int __terminated = 0;
+ static bool terminated = false;
struct signalfd_siginfo si;
ssize_t result;
int fd;
@@ -1699,13 +1940,13 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
* exit and fall through.
*/
case SIGTERM:
- if (__terminated == 0) {
+ if (!terminated) {
rl_replace_line("", 0);
rl_crlf();
g_main_loop_quit(main_loop);
}
- __terminated = 1;
+ terminated = true;
break;
}
diff --git a/configure.ac b/configure.ac
index e10659b8..ea33a000 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
-AC_INIT(bluez, 5.30)
+AC_INIT(bluez, 5.37)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
tar-pax no-dist-gzip dist-xz])
@@ -113,6 +113,20 @@ if (test -z "${path_dbussessionbusdir}"); then
fi
AC_SUBST(DBUS_SESSIONBUSDIR, [${path_dbussessionbusdir}])
+AC_ARG_ENABLE(backtrace, AC_HELP_STRING([--enable-backtrace],
+ [compile backtrace support]), [enable_backtrace=${enableval}])
+
+if (test "${enable_backtrace}" = "yes"); then
+ AC_CHECK_HEADER(elfutils/libdwfl.h, dummy=yes,
+ AC_MSG_ERROR(elfutils support is required))
+ AC_DEFINE(HAVE_BACKTRACE_SUPPORT, 1,
+ [Define to 1 if you have the backtrace support.])
+ BACKTRACE_CFLAGS=""
+ BACKTRACE_LIBS="-ldw"
+ AC_SUBST(BACKTRACE_CFLAGS)
+ AC_SUBST(BACKTRACE_LIBS)
+fi
+
AC_ARG_ENABLE(library, AC_HELP_STRING([--enable-library],
[install Bluetooth library]), [enable_library=${enableval}])
AM_CONDITIONAL(LIBRARY, test "${enable_library}" = "yes")
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index c815cf03..0eeb0ccd 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -102,6 +102,7 @@ Methods void StartDiscovery()
right after call to StartDiscovery.
Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.NotSupported
org.bluez.Error.Failed
#ifdef __TIZEN_PATCH__
@@ -230,6 +231,15 @@ Methods void StartDiscovery()
org.bluez.Error.InvalidArguments
org.bluez.Error.Failed
+ void SetLeStaticRandomAddress(boolean enable_random_address)
+
+ This method is used to set/reset LE static random address for the local
+ adapter when it supports the feature.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
void SetManufacturerData(array{byte} value)
This method is used to set Manufacturer data on a
@@ -311,7 +321,7 @@ Properties string Address [readonly]
value will fail.
When changing the Powered property the new state of
- this property will be updated via a PropertyChanged
+ this property will be updated via a PropertiesChanged
signal.
For any new adapter this settings defaults to false.
diff --git a/doc/advertising-api.txt b/doc/advertising-api.txt
index 7fb34eeb..4ee37bba 100644
--- a/doc/advertising-api.txt
+++ b/doc/advertising-api.txt
@@ -61,6 +61,11 @@ Properties string Type
Service Data elements to include. The keys are the
UUID to associate with the data.
+ bool IncludeTxPower
+
+ Includes the Tx Power in the advertising packet.
+ If missing, the Tx Power is not included.
+
LE Advertising Manager hierarchy
================================
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index 2e70931a..801ccb66 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -37,7 +37,7 @@ Object path /org/bluez
agent.
If an empty string is used it will fallback to
- "DisplayYesNo".
+ "KeyboardDisplay".
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.AlreadyExists
diff --git a/doc/coding-style.txt b/doc/coding-style.txt
index b3fbd2e3..f0bf880e 100644
--- a/doc/coding-style.txt
+++ b/doc/coding-style.txt
@@ -61,7 +61,7 @@ if (err || !S_ISDIR(st.st_mode))
M2: Multiple line comment
=========================
-If your comments have more then one line, please start it from the second line.
+If your comment has more than one line, please start it from the second line.
Example:
/*
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 290ff7d3..8141244f 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -235,6 +235,30 @@ Properties string Address [readonly]
Received Signal Strength Indicator of the remote
device (inquiry or advertising).
+ int16 TxPower [readonly, optional, experimental]
+
+ Advertised transmitted power level (inquiry or
+ advertising).
+
+ dict ManufacturerData [readonly, optional]
+
+ Manufacturer specific advertisement data. Keys are
+ 16 bits Manufacturer ID followed by its byte array
+ value.
+
+ dict ServiceData [readonly, optional]
+
+ Service advertisement data. Keys are the UUIDs in
+ string format followed by its byte array value.
+
+ array{object} GattServices [readonly, optional]
+
+ List of GATT service object paths. Each referenced
+ object exports the org.bluez.GattService1 interface and
+ represents a remote GATT service. This property will be
+ updated once all remote GATT services of this device
+ have been discovered and exported over D-Bus.
+
#ifdef __TIZEN_PATCH__
boolean GattConnected [readonly]
diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index 3329ffd8..d366bd1c 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -148,6 +148,10 @@ Properties string UUID [read-only]
"authenticated-signed-writes"
"reliable-write"
"writable-auxiliaries"
+ "encrypt-read"
+ "encrypt-write"
+ "encrypt-authenticated-read"
+ "encrypt-authenticated-write"
array{object} Descriptors [read-only]
@@ -213,6 +217,18 @@ Properties string UUID [read-only]
gets updated only after a successful read request, upon
which a PropertiesChanged signal will be emitted.
+ array{string} Flags [read-only]
+
+ Defines how the descriptor value can be used.
+
+ Possible values:
+
+ "read"
+ "write"
+ "encrypt-read"
+ "encrypt-write"
+ "encrypt-authenticated-read"
+ "encrypt-authenticated-write"
Profile hierarcy
================
@@ -261,9 +277,9 @@ must be available on the root service path. An example application hierarchy
containing two separate GATT services may look like this:
-> /com/example
+ | - org.freedesktop.DBus.ObjectManager
|
-> /com/example/service0
- | | - org.freedesktop.DBus.ObjectManager
| | - org.freedesktop.DBus.Properties
| | - org.bluez.GattService1
| |
@@ -280,7 +296,6 @@ containing two separate GATT services may look like this:
| - org.bluez.GattDescriptor1
|
-> /com/example/service1
- | - org.freedesktop.DBus.ObjectManager
| - org.freedesktop.DBus.Properties
| - org.bluez.GattService1
|
@@ -300,21 +315,21 @@ Service org.bluez
Interface org.bluez.GattManager1 [Experimental]
Object path [variable prefix]/{hci0,hci1,...}
-Methods void RegisterService(object service, dict options)
+Methods void RegisterApplication(object application, dict options)
- Registers a local GATT service hierarchy as described
+ Registers a local GATT services hierarchy as described
above.
- "service" object path together with the D-Bus system
- bus connection ID define the identification of the
- application registering a GATT based service.
+ The application object path together with the D-Bus
+ system bus connection ID define the identification of
+ the application registering a GATT based service.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.AlreadyExists
- void UnregisterService(object service)
+ void UnregisterApplication(object application)
- This unregisters the service that has been
+ This unregisters the services that has been
previously registered. The object path parameter
must match the same value that has been used
on registration.
diff --git a/doc/maintainer-guidelines.txt b/doc/maintainer-guidelines.txt
index fef90c89..21162d4e 100644
--- a/doc/maintainer-guidelines.txt
+++ b/doc/maintainer-guidelines.txt
@@ -99,7 +99,7 @@ verified first:
- Check that the names are acceptible with other maintainers
- Ensure that the file modes are correct
- Verify that the license & copyright headers are correct
- - If the file is supposed to be part of the release taraball,
+ - If the file is supposed to be part of the release tarball,
make sure that it gets picked up by 'make dist' (particularly
important for documentation or other files that are not code)
diff --git a/doc/media-api.txt b/doc/media-api.txt
index b17a1519..b5ad2db1 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -71,43 +71,43 @@ Media Control hierarchy
=======================
Service org.bluez
-Interface org.bluez.MediaControl1 [Deprecated]
+Interface org.bluez.MediaControl1
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-Methods void Play()
+Methods void Play() [Deprecated]
Resume playback.
- void Pause()
+ void Pause() [Deprecated]
Pause playback.
- void Stop()
+ void Stop() [Deprecated]
Stop playback.
- void Next()
+ void Next() [Deprecated]
Next item.
- void Previous()
+ void Previous() [Deprecated]
Previous item.
- void VolumeUp()
+ void VolumeUp() [Deprecated]
Adjust remote volume one step up
- void VolumeDown()
+ void VolumeDown() [Deprecated]
Adjust remote volume one step down
- void FastForward()
+ void FastForward() [Deprecated]
Fast forward playback, this action is only stopped
when another method in this interface is called.
- void Rewind()
+ void Rewind() [Deprecated]
Rewind playback, this action is only stopped
when another method in this interface is called.
@@ -116,6 +116,10 @@ Properties
boolean Connected [readonly]
+ object Player [readonly, optional]
+
+ Addressed Player object path.
+
MediaPlayer1 hierarchy
======================
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index b4ddf770..b27990d6 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -23,7 +23,9 @@ Linux kernel v3.15 Version 1.5
Linux kernel v3.16 Version 1.6
Linux kernel v3.17 Version 1.7
Linux kernel v3.19 Version 1.8
-Linux kernel v4.1 Version 1.9 (not yet released)
+Linux kernel v4.1 Version 1.9
+Linux kernel v4.2 Version 1.10
+Linux kernel v4.5 Version 1.11 (not yet released)
Version 1.1 introduces Set Device ID command.
@@ -55,10 +57,19 @@ an extra setting for enabling SSP debug mode.
Version 1.8 introduces Start Service Discovery command. It also adds new
Long Term Key types for LE Secure Connection feature.
-Version 1.9 introduces a new static address setting and allows the usage
-of Set Fast Connectable when controller is powered off. The existing Set
-Advertising command gained an extra setting for enabling undirected
-connectable advertising.
+Version 1.9 introduces Read Local Out Of Band Extended, Data, Read Extended
+Controller Index List, Read Advertising Features, Add Advertising and Remove
+Advertising commands. It also introduces Extended Index Added, Extended Index
+Removed, Local Out Of Band Extended Data Updated, Advertising Added and
+Advertising Removed events. The existing Set Advertising command gained an
+extra setting for enabling undirected connectable advertising. It provides
+support for a new static address setting and allows the usage of Set Fast
+Connectable when controller is powered off.
+
+Version 1.10 does not introduce any new command or event. It extends the
+advertising feature to support 5 parallel advertising instances.
+
+Version 1.11 introduces Get Advertising Size Information command.
Example
@@ -239,7 +250,7 @@ Read Controller Information Command
Name (249 Octets)
Short_Name (11 Octets)
- This command is used to retreive the current state and basic
+ This command is used to retrieve the current state and basic
information of a controller. It is typically used right after
getting the response to the Read Controller Index List command
or an Index Added event.
@@ -305,6 +316,15 @@ Set Powered Command
switching the controller off will expire this timeout and
disable discoverable.
+ Settings programmed via Set Advertising and Add/Remove
+ Advertising while the controller was powered off will be activated
+ when powering the controller on.
+
+ Switching the controller off will permanently cancel and remove
+ all advertising instances with a timeout set, i.e. time limited
+ advertising instances are not being remembered across power cycles.
+ Advertising Removed events will be issued accordingly.
+
This command generates a Command Complete event on success or
a Command Status event on failure.
@@ -377,7 +397,7 @@ Set Connectable Command
and for LE controllers it changes the advertising type. For
dual mode controllers it affects both settings.
- For LE capable controllers the connectable setting takes affect
+ For LE capable controllers the connectable setting takes effect
when advertising is enabled (peripheral) or when directed
advertising events are received (central).
@@ -585,6 +605,10 @@ Set Low Energy Command
In case the kernel subsystem does not support Low Energy or the
controller does not either, the command will fail regardless.
+ Disabling LE support will permanently disable and remove all
+ advertising instances configured with the Add Advertising
+ command. Advertising Removed events will be issued accordingly.
+
This command generates a Command Complete event on success or
a Command Status event on failure.
@@ -738,8 +762,8 @@ Load Link Keys Command
This command is used to feed the kernel with currently known
link keys. The command does not need to be called again upon the
- receiption of New Link Key events since the kernel updates its
- list automatically.
+ receipt of New Link Key events since the kernel updates its list
+ automatically.
The Debug_Keys parameter is used to tell the kernel whether to
accept the usage of debug keys or not. The allowed values for
@@ -802,7 +826,7 @@ Load Long Term Keys Command
This command is used to feed the kernel with currently known
(SMP) Long Term Keys. The command does not need to be called
- again upon the receiption of New Long Term Key events since the
+ again upon the receipt of New Long Term Key events since the
kernel updates its list automatically.
Possible values for the Address_Type parameter:
@@ -874,7 +898,7 @@ Get Connections Command
Address2 { }
...
- This command is used to retreive a list of currently connected
+ This command is used to retrieve a list of currently connected
devices.
Possible values for the Address_Type parameter:
@@ -999,7 +1023,7 @@ Pair Device Command
This command is used to trigger pairing with a remote device.
The IO_Capability command parameter is used to temporarily (for
- this pairing event only) override the global IO Capaility (set
+ this pairing event only) override the global IO Capability (set
using the Set IO Capability command).
Possible values for the Address_Type parameter:
@@ -1026,7 +1050,7 @@ Pair Device Command
To allow tracking of which resolvable random address changed
into which identity address, the New Identity Resolving Key
- event will be send before receiving Command Complete event
+ event will be sent before receiving Command Complete event
for this command.
This command can only be used when the controller is powered.
@@ -1467,7 +1491,7 @@ Block Device Command
Address_Type (1 Octet)
This command is used to add a device to the list of devices
- which should be blocked from being connect to the local
+ which should be blocked from being connected to the local
controller.
Possible values for the Address_Type parameter:
@@ -1475,7 +1499,7 @@ Block Device Command
1 LE Public
2 LE Random
- For Low Energy devices, the blocking of a device take presedence
+ For Low Energy devices, the blocking of a device takes precedence
over auto-connection actions provided by Add Device. Blocked
devices will not be auto-connected or even reported when found
during background scanning. If the controller is connectable
@@ -1543,11 +1567,11 @@ Set Device ID Command
0x0000 Disable Device ID
0x0001 Bluetooth SIG
- 0x0002 USB Implementer’s Forum
+ 0x0002 USB Implementer's Forum
- The information are put into the EIR data. If the controller does
+ The information is put into the EIR data. If the controller does
not support EIR or if SSP is disabled, this command will still
- succeed. The information are stored for later use and will survive
+ succeed. The information is stored for later use and will survive
toggling SSP on and off.
This command generates a Command Complete event on success or
@@ -1576,7 +1600,7 @@ Set Advertising Command
Using value 0x01 means that when connectable setting is disabled,
the advertising happens with undirected non-connectable advertising
- packets and a non-resovable random address is used. If connectable
+ packets and a non-resolvable random address is used. If connectable
setting is enabled, then undirected connectable advertising packets
and the identity address or resolvable private address are used.
@@ -1592,8 +1616,12 @@ Set Advertising Command
The value 0x02 should be the preferred mode of operation when
implementing peripheral mode.
- Using this command will temporarily deactive any configuration
+ Using this command will temporarily deactivate any configuration
made by the Add Advertising command. This command takes precedence.
+ Once a Set Advertising command with value 0x00 is issued any
+ previously made configurations via Add/Remove Advertising, including
+ such changes made while Set Advertising was active, will be re-
+ enabled.
A pre-requisite is that LE is already enabled, otherwise this
command will return a "rejected" response.
@@ -1794,12 +1822,13 @@ Set Privacy Command
discoverable and also when pairing is initiated.
With value 0x02 the kernel will use privacy mode with resolvable
- private address. In case the conroller is bondable and discoverable
- the identity address is used. Also when pairing is initiated, the
- connection will be established with the identity address.
+ private address. In case the controller is bondable and
+ discoverable the identity address is used. Also when pairing is
+ initiated, the connection will be established with the identity
+ address.
Exposing the identity address when bondable and discoverable or
- during initated pairing can be a privacy issue. For dual-mode
+ during initiated pairing can be a privacy issue. For dual-mode
controllers this can be neglected since its public address will
be exposed over BR/EDR anyway. The benefit of exposing the
identity address for pairing purposes is that it makes matching
@@ -1813,7 +1842,7 @@ Set Privacy Command
When the controller has a public address (mandatory for dual-mode
controllers) it is used as identity address. In case the controller
is single mode LE only without a public address, it is required
- to configure a static random andress first. The privacy mode can
+ to configure a static random address first. The privacy mode can
only be enabled when an identity address is available.
The Identity_Resolving_Key is the local key assigned for the local
@@ -1842,7 +1871,7 @@ Load Identity Resolving Keys Command
This command is used to feed the kernel with currently known
identity resolving keys. The command does not need to be called
- again upon the receiption of New Identity Resolving Key events
+ again upon the receipt of New Identity Resolving Key events
since the kernel updates its list automatically.
Possible values for the Address_Type parameter:
@@ -2024,17 +2053,17 @@ Add Device Command
2 Auto-connect remote device
With the Action 0, when the device is found, a new Device Found
- event will be send indicating this device is available. This
+ event will be sent indicating this device is available. This
action is only valid for LE Public and LE Random address types.
With the Action 1, the device is allowed to connect. For BR/EDR
address type this means an incoming connection. For LE Public
and LE Random address types, a connection will be established
to devices using directed advertising. If successful a Device
- Connected event will be send.
+ Connected event will be sent.
With the Action 2, when the device is found, it will be connected
- and if successful a Device Connected event will be send. This
+ and if successful a Device Connected event will be sent. This
action is only valid for LE Public and LE Random address types.
When a device is blocked using Block Device command, then it is
@@ -2097,7 +2126,7 @@ Load Connection Parameters Command
Address (6 Octets)
Address_Type (1 Octet)
Min_Connection_Interval (2 Octets)
- Max_Connection_Interval (2 Octes)
+ Max_Connection_Interval (2 Octets)
Connection_Latency (2 Octets)
Supervision_Timeout (2 Octets)
}
@@ -2167,7 +2196,7 @@ Read Controller Configuration Information Command
Supported_Options (4 Octets)
Missing_Options (4 Octets)
- This command is used to retreive the supported configuration
+ This command is used to retrieve the supported configuration
options of a controller and the missing configuration options.
The missing options are required to be configured before the
@@ -2228,7 +2257,7 @@ Set External Configuration Command
can be expected that it will be announced via Index Added event.
Wrongly configured controllers might still cause an error when
- trying to power them via Set Powered commmand.
+ trying to power them via Set Powered command.
This command generates a Command Complete event on success or a
Command Status event on failure.
@@ -2265,8 +2294,8 @@ Set Public Address Command
For a fully configured controller, the current controller index
will become invalid and an Unconfigured Index Removed event will
- be send. Once the address has been successfully changed an Index
- Added event will be send. There is no guarantee that the controller
+ be sent. Once the address has been successfully changed an Index
+ Added event will be sent. There is no guarantee that the controller
index stays the same.
All previous configured parameters and settings are lost when
@@ -2465,7 +2494,7 @@ Read Extended Controller Index List Command
0x01 Unconfigured Controller (BR/EDR and/or LE)
0x02 Alternate MAC/PHY Controller (AMP)
- The 0x00 and 0x01 types indiciate a primary BR/EDR and/or LE
+ The 0x00 and 0x01 types indicate a primary BR/EDR and/or LE
controller. The difference is just if they need extra configuration
or if they are fully configured.
@@ -2556,7 +2585,7 @@ Read Advertising Features Command
not be set.
The Flags bit 5 indicates support for automatically adding the
- Apperance value to the scan response data. Users of this flag
+ Appearance value to the scan response data. Users of this flag
will decrease the Max_Scan_Rsp_len by 4 octets. The Appearance
field will be added in front of the scan response data provided
by the user. If the appearance value is not supported, then this
@@ -2581,7 +2610,7 @@ Read Advertising Features Command
however might decrease the actual available length in these
data fields.
- With Num_Instances and Instance array the current occupied
+ With Num_Instances and Instance array the currently occupied
Instance identifiers can be retrieved.
This command generates a Command Complete event on success or
@@ -2610,9 +2639,11 @@ Add Advertising Command
can be used to switch a Bluetooth Low Energy controller into
advertising mode.
- Added advertising information with this command will be ignored
- when using the Set Advertising command to enable advertising. The
- usage of Set Advertising command take precedence over this command.
+ Added advertising information with this command will not be visible
+ immediately if advertising is enabled via the Set Advertising
+ command. The usage of the Set Advertising command takes precedence
+ over this command. Instance information is stored and will be
+ advertised once advertising via Set Advertising has been disabled.
The Instance identifier is a value between 1 and the number of
supported instances. The value 0 is reserved.
@@ -2655,26 +2686,45 @@ Add Advertising Command
broadcaster role.
The Duration parameter configures the length of an Instance. The
- value is in seconds and a value of 0 indicates an automatic choice
- for the Duration. If only one advertising Instance has been added,
- then the Duration value will be ignored. It only applies for the
- case where multiple Instances are configured. In that case every
- Instance will be available for the Duration time and after that
- it switches to the next one. This is a simple round-robin based
- approach.
+ value is in seconds.
+
+ A value of 0 indicates a default value is chosen for the
+ Duration. The default is 2 seconds.
+
+ If only one advertising Instance has been added, then the Duration
+ value will be ignored. It only applies for the case where multiple
+ Instances are configured. In that case every Instance will be
+ available for the Duration time and after that it switches to
+ the next one. This is a simple round-robin based approach.
The Timeout parameter configures the life-time of an Instance. In
case the value 0 is used it indicates no expiration time. If a
- timeout value is provided, then the advertising Instace will be
+ timeout value is provided, then the advertising Instance will be
automatically removed when the timeout passes. The value for the
timeout is in seconds. Powering down a controller will invalidate
all advertising Instances and it is not possible to add a new
Instance with a timeout when the controller is powered down.
- When a Timeout is provided, then the Duration substracts from
+ When a Timeout is provided, then the Duration subtracts from
the actual Timeout value of that Instance. For example an Instance
- with Timeout of 6 and Duration of 2 will be scheduled exactly 3
- times. Other Instances have no influence on the Timeout.
+ with Timeout of 5 and Duration of 2 will be scheduled exactly 3
+ times, twice with 2 seconds and once with one second. Other
+ Instances have no influence on the Timeout.
+
+ Re-adding an already existing instance (i.e. issuing the Add
+ Advertising command with an Instance identifier of an existing
+ instance) will update that instance's configuration.
+
+ An instance being added or changed while another instance is
+ being advertised will not be visible immediately but only when
+ the new/changed instance is being scheduled by the round robin
+ advertising algorithm.
+
+ Changes to an instance that is currently being advertised will
+ cancel that instance and switch to the next instance. The changes
+ will be visible the next time the instance is scheduled for
+ advertising. In case a single instance is active, this means
+ that changes will be visible right away.
A pre-requisite is that LE is already enabled, otherwise this
command will return a "rejected" response.
@@ -2707,6 +2757,17 @@ Remove Advertising Command
When the Instance parameter is zero, then all previously added
advertising Instances will be removed.
+ Removing advertising information with this command will not be
+ visible as long as advertising is enabled via the Set Advertising
+ command. The usage of the Set Advertising command takes precedence
+ over this command. Changes to Instance information are stored and
+ will be advertised once advertising via Set Advertising has been
+ disabled.
+
+ Removing an instance while it is being advertised will immediately
+ cancel the instance, even when it has been advertised less then its
+ configured Timeout or Duration.
+
This command can be used when the controller is not powered and
all settings will be programmed once powered.
@@ -2717,6 +2778,91 @@ Remove Advertising Command
Invalid Index
+Get Advertising Size Information Command
+========================================
+
+ Command Code: 0x0040
+ Controller Index: <controller id>
+ Command Parameters: Instance (1 Octet)
+ Flags (4 Octets)
+ Return Parameters: Instance (1 Octet)
+ Flags (4 Octets)
+ Max_Adv_Data_Len (1 Octet)
+ Max_Scan_Rsp_Len (1 Octet)
+
+ The Read Advertising Features command returns the overall maximum
+ size of advertising data and scan response data fields. That size is
+ valid when no Flags are used. However when certain Flags are used,
+ then the size might decrease. This command can be used to request
+ detailed information about the maximum available size.
+
+ The following Flags values are defined:
+
+ 0 Switch into Connectable mode
+ 1 Advertise as Discoverable
+ 2 Advertise as Limited Discoverable
+ 3 Add Flags field to Adv_Data
+ 4 Add TX Power field to Adv_Data
+ 5 Add Appearance field to Scan_Rsp
+ 6 Add Local Name in Scan_Rsp
+
+ To get accurate information about the available size, the same Flags
+ values should be used with the Add Advertising command.
+
+ The Max_Adv_Data_Len and Max_Scan_Rsp_Len fields provide information
+ about the maximum length of the data fields for the given Flags
+ values. When the Flags field is zero, then these fields would contain
+ the same values as Read Advertising Features.
+
+ Possible errors: Invalid Parameters
+ Invalid Index
+
+
+Start Limited Discovery Command
+===============================
+
+ Command Code: 0x0041
+ Controller Index: <controller id>
+ Command Parameters: Address_Type (1 Octet)
+ Return Parameters: Address_Type (1 Octet)
+
+ This command is used to start the process of discovering remote
+ devices using the limited discovery procedure. A Device Found event
+ will be sent for each discovered device.
+
+ Possible values for the Address_Type parameter are a bit-wise or
+ of the following bits:
+
+ 0 BR/EDR
+ 1 LE Public
+ 2 LE Random
+
+ By combining these e.g. the following values are possible:
+
+ 1 BR/EDR
+ 6 LE (public & random)
+ 7 BR/EDR/LE (interleaved discovery)
+
+ The limited discovery uses active scanning for Low Energy scanning
+ and will search for devices with the limited discoverability flag
+ configured. On BR/EDR it uses LIAC and filters on the limited
+ discoverability flag of the class of device.
+
+ When the discovery procedure starts the Discovery event will
+ notify this similar to Start Discovery.
+
+ This command can only be used when the controller is powered.
+
+ This command generates a Command Complete event on success
+ or failure.
+
+ Possible errors: Busy
+ Not Supported
+ Invalid Parameters
+ Not Powered
+ Invalid Index
+
+
Command Complete Event
======================
@@ -2839,7 +2985,7 @@ New Link Key Event
PIN_Length (1 Octet)
}
- This event indicates that a new link key has bee generated for a
+ This event indicates that a new link key has been generated for a
remote device.
The Store_Hint parameter indicates whether the host is expected
@@ -2865,7 +3011,7 @@ New Link Key Event
0x07 Unauthenticated Combination key from P-256
0x08 Authenticated Combination key from P-256
- Receiving this event indicates that a pairing procecure has
+ Receiving this event indicates that a pairing procedure has
been completed.
@@ -2913,7 +3059,7 @@ New Long Term Key Event
0x03 Authenticated key from P-256
0x04 Debug key from P-256
- Receiving this event indicates that a pairing procecure has
+ Receiving this event indicates that a pairing procedure has
been completed.
@@ -3218,7 +3364,7 @@ Device Unpaired Event
2 LE Random
For devices using resolvable random addresses with a known
- identity resolving key, the event paramters will contain
+ identity resolving key, the event parameters will contain
the identity. After receiving this event, the device will
become essentially private again.
@@ -3396,7 +3542,7 @@ New Connection Parameter Event
Address (6 Octets)
Address_Type (1 Octet)
Min_Connection_Interval (2 Octets)
- Max_Connection_Interval (2 Octes)
+ Max_Connection_Interval (2 Octets)
Connection_Latency (2 Octets)
Supervision_Timeout (2 Octets)
}
diff --git a/doc/pics-opp.txt b/doc/pics-opp.txt
new file mode 100644
index 00000000..fb4746d9
--- /dev/null
+++ b/doc/pics-opp.txt
@@ -0,0 +1,187 @@
+OPP PICS for the PTS tool.
+
+PTS version: 6.2.0
+
+* - different than PTS defaults
+# - not yet implemented/supported
+
+M - mandatory
+O - optional
+
+ Roles
+-------------------------------------------------------------------------------
+Parameter Name Selected Description
+-------------------------------------------------------------------------------
+TSPC_OPP_1_1 True (*) Role: Object Push Client (C.1)
+TSPC_OPP_1_2 True (*) Role: Object Push Server (C.1)
+-------------------------------------------------------------------------------
+C.1: Mandatory to support at least one of the defined roles.
+-------------------------------------------------------------------------------
+
+
+ Client Profile Version
+-------------------------------------------------------------------------------
+Parameter Name Selected Description
+-------------------------------------------------------------------------------
+TSPC_OPP_1b_1 False Client supports OPP version 1.1. (C.1)
+TSPC_OPP_1b_2 True (*) Client supports OPP version 1.2. (C.1)
+-------------------------------------------------------------------------------
+C.1: It is mandatory to support at least one of the profile versions.
+-------------------------------------------------------------------------------
+
+
+ Client Application Features
+-------------------------------------------------------------------------------
+Parameter Name Selected Description
+-------------------------------------------------------------------------------
+TSPC_OPP_2_1 True Client: Perform Service Discovery request (M)
+TSPC_OPP_2_2 True Client: Authentication/PIN exchange supported.
+ (M)
+TSPC_OPP_2_2a True (*) Client: Require Authentication/PIN by default.
+ (O)
+TSPC_OPP_2_3 True Client: Object Push (M)
+TSPC_OPP_2_4 True (*) Client: vCard 2.1 (C.3)
+TSPC_OPP_2_5 False Client: vCalender 1.0 (O)
+TSPC_OPP_2_6 False Client: vMsg as defined in IrMC 1.1 (O)
+TSPC_OPP_2_7 False Client: vNote as defined in IrMC 1.1 (O)
+TSPC_OPP_2_8 True (*) Client: Support content formats other than those
+ declared in TSPC_OPP_2_4 through
+ TSPC_OPP_2_7. (O)
+TSPC_OPP_2_8a False Client: Support specific set of other content
+ formats. (C.4)
+TSPC_OPP_2_8b True (*) Client: Support all content formats. (C.4)
+TSPC_OPP_2_9 True (*) Client: Push multiple vCard objects. (O)
+TSPC_OPP_2_9a True (*) Client: Push multiple vCard objects using
+ different PUT operations. (C.5)
+TSPC_OPP_2_9b False Client: Push multiple vCard objects using the
+ same PUT operation. (C.5)
+TSPC_OPP_2_10 True (*) Client: Push multiple vCalender objects. (O)
+TSPC_OPP_2_10a True Client: Push multiple vCalendar objects using
+ different PUT operations. (C.6)
+TSPC_OPP_2_10b False Client: Push multiple vCalendar objects using
+ the same PUT operation. (C.6)
+TSPC_OPP_2_11 True (*) Client: Push multiple vMsg objects. (O)
+TSPC_OPP_2_11a True (*) Client: Push multiple vMsg objects using
+ different PUT operations. (C.7)
+TSPC_OPP_2_11b False Client: Push multiple vMsg objects using the
+ same PUT operation. (C.7)
+TSPC_OPP_2_12 True (*) Client: Push multiple vNote objects. (O)
+TSPC_OPP_2_12a True (*) Client: Push multiple vNote objects using
+ different PUT operations. (C.8)
+TSPC_OPP_2_12b False Client: Push multiple vNote objects using the
+ same PUT operation. (C.8)
+TSPC_OPP_2_13 True (*) Client: Pull business card (O)
+TSPC_OPP_2_14 True (*) Client: vCard 2.1 (C.1)
+TSPC_OPP_2_15 True (*) Client: Exchange business card (O)
+TSPC_OPP_2_16 False Client: vCard 2.1 (C.2)
+TSPC_OPP_2_17 True (*) GOEP v2 (C.9)
+TSPC_OPP_2_18 True (*) GOEP v2 Backward Compatibility (C.9)
+TSPC_OPP_2_19 True (*) OBEX over L2CAP (C.9)
+TSPC_OPP_2_20 False OBEX Reliable Session (C.10)
+TSPC_OPP_2_21 False OBEX SRM (C.10)
+TSPC_OPP_2_22 False Send OBEX SRMP header (C.10)
+TSPC_OPP_2_23 False Receive OBEX SRMP header (C.11)
+-------------------------------------------------------------------------------
+C.1: Mandatory to Support IF (TSPC_OPP_2_13) Business Card Pull is supported.
+C.2: Mandatory to Support IF (TSPC_OPP_2_15) Business Card Exchange is
+ supported.
+C.3: vCard 2.1 support is required for devices containing phonebook
+ applications. vCard 2.1 support optional for other devices.
+C.4: Mandatory to support one of TSPC_OPP_2_8a or TSPC_OPP_2_8b if TSPC_OPP_2_8
+ is supported. Otherwise, both items are excluded.
+C.5: Mandatory to support at least one of TSPC_OPP_2_9a and TSPC_OPP_2_9b if
+ TSPC_OPP_2_9 is supported. Otherwise, both items are excluded.
+C.6: Mandatory to support at least one of TSPC_OPP_2_10a and TSPC_OPP_2_10b if
+ TSPC_OPP_2_10 is supported. Otherwise, both items are excluded.
+C.7: Mandatory to support at least one of TSPC_OPP_2_11a and TSPC_OPP_2_11b if
+ TSPC_OPP_2_11 is supported. Otherwise, both items are excluded.
+C.8: Mandatory to support at least one of TSPC_OPP_2_12a and TSPC_OPP_2_12b if
+ TSPC_OPP_2_12 is supported. Otherwise, both items are excluded.
+C.9: Mandatory if TSPC_OPP_1b_2 supported.
+C.10: Optional to support if TSPC_OPP_1b_2 supported else excluded.
+C.11: Mandatory if TSPC_OPP_17 and TSPC_OPP_21 supported else excluded.
+-------------------------------------------------------------------------------
+
+
+ Server Profile Version
+-------------------------------------------------------------------------------
+Parameter Name Selected Description
+-------------------------------------------------------------------------------
+TSPC_OPP_2b_1 False Server supports OPP version 1.1.
+TSPC_OPP_2b_2 True (*) Server supports OPP version 1.2.
+-------------------------------------------------------------------------------
+C.1: It is mandatory to support at least one of the profile versions.
+-------------------------------------------------------------------------------
+
+
+ Server Application Features
+-------------------------------------------------------------------------------
+Parameter Name Selected Description
+-------------------------------------------------------------------------------
+TSPC_OPP_3_1 True Server: Provide information on supported
+ contents type on service discovery
+ request. (M)
+TSPC_OPP_3_2 True Server: Authentication/PIN exchange supported.
+ (M)
+TSPC_OPP_3_3 True Server: Object Push (M)
+TSPC_OPP_3_3a True (*) Server: Receive multiple objects in the same
+ PUT operation. (O)
+TSPC_OPP_3_4 True (*) Server: vCard 2.1 (C.3)
+TSPC_OPP_3_5 False Server: vCalender 1.0 format (O)
+TSPC_OPP_3_6 False Server: vMsg as defined in IrMC 1.1 (O)
+TSPC_OPP_3_7 False Server: vNote as defined in IrMC 1.1 (O)
+TSPC_OPP_3_8 True (*) Server: Support content formats other than those
+ declared in TSPC_OPP_3_4 through
+ TSPC_OPP_3_7. (O)
+TSPC_OPP_3_8a False Server: Support specific set of other content
+ formats. (C.4)
+TSPC_OPP_3_8b True (*) Server: Support all content formats. (C.4)
+TSPC_OPP_3_9 True (*) Server: Object Push vCard reject. (O)
+TSPC_OPP_3_10 True (*) Server: Object Push vCal reject. (O)
+TSPC_OPP_3_11 True (*) Server: Object Push vMsg reject. (O)
+TSPC_OPP_3_12 True (*) Server: Object Push vNote reject. (O)
+TSPC_OPP_3_13 True (*) Server: Business card pull (O.1)
+TSPC_OPP_3_14 True (*) Server: vCard 2.1 (C.1)
+TSPC_OPP_3_15 True (*) Server: Business card pull reject. (O)
+TSPC_OPP_3_16 True (*) Server: Business card exchange (O.2)
+TSPC_OPP_3_17 True (*) Server: vCard 2.1 (C.2)
+TSPC_OPP_3_18 True (*) Server: Business card exchange reject. (O)
+TSPC_OPP_3_19 True (*) GOEP v2 (C.5)
+TSPC_OPP_3_20 True (*) GOEP v2 Backward Compatibility (C.5)
+TSPC_OPP_3_21 True (*) OBEX over L2CAP (C.5)
+TSPC_OPP_3_22 False OBEX Reliable Session (C.16)
+TSPC_OPP_3_23 False OBEX SRM (C.6)
+TSPC_OPP_3_24 False Send OBEX SRMP header (C.6)
+TSPC_OPP_3_25 False Receive OBEX SRMP header (C.7)
+-------------------------------------------------------------------------------
+O.1: IF NOT Supported, an error message must be sent on request for Business
+ Card Pull.
+O.2: IF NOT Supported, an error message must be sent on request for Business
+ Card Exchange.
+C.1: Mandatory to Support IF (TSPC_OPP_3_13) Business Card Pull is supported.
+C.2: Mandatory to Support IF (TSPC_OPP_3_16) Business Card Exchange is
+ supported.
+C.3: vCard 2.1 support is required for devices containing phonebook
+ applications. vCard 2.1 support optional for other devices.
+C.4: Mandatory to support one of TSPC_OPP_3_8a or TSPC_OPP_3_8b if TSPC_OPP_3_8
+ is supported. Otherwise, both items are excluded.
+C.5: Mandatory if TSPC_OPP_2b_2 supported.
+C.6: Optional to support if TSPC_OPP_2b_2 supported, else excluded.
+C.7: Mandatory if TSPC_OPP_3_19 and TSPC_OPP_3_23 supported else excluded.
+-------------------------------------------------------------------------------
+
+
+ Additional OPP Capabilities
+-------------------------------------------------------------------------------
+Parameter Name Selected Description
+-------------------------------------------------------------------------------
+TSPC_OPP_4_1 False Abort-Push Operation (O)
+TSPC_OPP_4_2 False Intentionally Left Blank (N/A)
+TSPC_OPP_4_3 True (*) Multiple vCards transferred as a single vObject
+ (C.1)
+TSPC_OPP_4_4 True (*) Multiple vCards transfer (C.1)
+TSPC_OPP_4_5 True (*) vCards with multiple Phone Number Fields (C.1)
+TSPC_OPP_4_6 True (*) Push vCal to Different Time Zone Server (C.1)
+-------------------------------------------------------------------------------
+C.1: Optional if TSPC_OPP_1_2 is supported, otherwise excluded.
+-------------------------------------------------------------------------------
diff --git a/doc/pixit-opp.txt b/doc/pixit-opp.txt
new file mode 100644
index 00000000..b7461d6f
--- /dev/null
+++ b/doc/pixit-opp.txt
@@ -0,0 +1,27 @@
+OPP PIXIT for the PTS tool.
+
+PTS version: 6.2.0
+
+* - different than PTS defaults
+& - should be set to IUT Bluetooth address
+
+ Required PIXIT settings
+-------------------------------------------------------------------------------
+Parameter Name Value
+-------------------------------------------------------------------------------
+TSPX_supported_extension bmp
+TSPX_unsupported_extension pts
+TSPX_client_class_of_device 100104
+TSPX_server_class_of_device 100104
+TSPX_auth_password 0000
+TSPX_auth_user_id PTS
+TSPX_l2cap_psm 1003
+TSPX_rfcomm_channel 8
+TSPX_no_confirmations FALSE
+TSPX_bd_addr_iut 112233445566 (*&)
+TSPX_delete_link_key FALSE
+TSPX_pin_code 0000
+TSPX_security_enabled FALSE
+TSPX_time_guard 300000
+TSPX_use_implicit_send TRUE
+-------------------------------------------------------------------------------
diff --git a/doc/pts-opp.txt b/doc/pts-opp.txt
new file mode 100644
index 00000000..832028c4
--- /dev/null
+++ b/doc/pts-opp.txt
@@ -0,0 +1,119 @@
+PTS test results for OPP
+
+PTS version: 6.2.0
+Tested: 26-Aug-2015
+
+Results:
+PASS test passed
+FAIL test failed
+INC test is inconclusive
+N/A test is disabled due to PICS setup
+NONE test result is none
+
+-------------------------------------------------------------------------------
+Test Name Result Notes
+-------------------------------------------------------------------------------
+TC_CLIENT_BC_BV_02_I PASS
+TC_CLIENT_BC_BV_04_I PASS
+TC_CLIENT_BCE_BV_01_I PASS
+TC_CLIENT_BCE_BV_03_I N/A
+TC_CLIENT_BCE_BV_04_I PASS
+TC_CLIENT_BCE_BV_05_I PASS
+TC_CLIENT_BCE_BV_06_I PASS
+TC_CLIENT_BCE_BV_07_I PASS
+TC_CLIENT_BCP_BV_01_I PASS
+TC_CLIENT_BCP_BV_02_I PASS
+TC_CLIENT_BCP_BV_03_I N/A
+TC_CLIENT_BCP_BV_04_I PASS
+TC_CLIENT_BCP_BV_05_I PASS
+TC_CLIENT_CON_BV_01_C PASS
+TC_CLIENT_OPH_BI_01_C PASS
+TC_CLIENT_OPH_BV_01_I PASS
+TC_CLIENT_OPH_BV_02_I N/A
+TC_CLIENT_OPH_BV_03_I PASS
+TC_CLIENT_OPH_BV_04_I PASS
+TC_CLIENT_OPH_BV_05_I PASS
+TC_CLIENT_OPH_BV_07_I N/A
+TC_CLIENT_OPH_BV_08_I PASS
+TC_CLIENT_OPH_BV_09_I N/A
+TC_CLIENT_OPH_BV_10_I N/A
+TC_CLIENT_OPH_BV_11_I N/A
+TC_CLIENT_OPH_BV_12_I PASS
+TC_CLIENT_OPH_BV_13_I N/A
+TC_CLIENT_OPH_BV_14_I N/A
+TC_CLIENT_OPH_BV_15_I N/A
+TC_CLIENT_OPH_BV_16_I PASS
+TC_CLIENT_OPH_BV_17_I N/A
+TC_CLIENT_OPH_BV_18_I N/A
+TC_CLIENT_OPH_BV_19_I PASS Send file other than vCard
+TC_CLIENT_OPH_BV_20_I PASS
+TC_CLIENT_OPH_BV_22_I PASS Send file greater than 2 MB
+TC_CLIENT_OPH_BV_23_I N/A
+TC_CLIENT_OPH_BV_24_I N/A
+TC_CLIENT_OPH_BV_25_I N/A
+TC_CLIENT_OPH_BV_26_I N/A
+TC_CLIENT_SRM_BV_01_C N/A
+TC_CLIENT_SRM_BV_03_C N/A
+TC_CLIENT_SRM_BV_05_C N/A
+TC_CLIENT_SRM_BV_07_C N/A
+TC_CLIENT_SRMP_BI_01_C N/A
+TC_CLIENT_SRMP_BV_01_C N/A
+TC_CLIENT_SRMP_BV_04_C N/A
+TC_CLIENT_SRMP_BV_05_C N/A
+TC_CLIENT_SRMP_BV_06_C N/A
+TC_SERVER_BC_BV_01_I PASS
+TC_SERVER_BC_BV_03_I PASS
+TC_SERVER_BCE_BV_01_I PASS
+TC_SERVER_BCE_BV_03_I PASS
+TC_SERVER_BCE_BV_04_I PASS
+TC_SERVER_BCE_BV_05_I PASS
+TC_SERVER_BCE_BV_06_I PASS
+TC_SERVER_BCE_BV_07_I PASS
+TC_SERVER_BCP_BV_01_I PASS
+TC_SERVER_BCP_BV_02_I N/A
+TC_SERVER_BCP_BV_03_I PASS
+TC_SERVER_BCP_BV_04_I PASS
+TC_SERVER_BCP_BV_05_I PASS
+TC_SERVER_CON_BV_02_C PASS
+TC_SERVER_OPH_BV_01_I PASS
+TC_SERVER_OPH_BV_02_I PASS
+TC_SERVER_OPH_BV_03_I PASS
+TC_SERVER_OPH_BV_04_I PASS
+TC_SERVER_OPH_BV_05_I PASS
+TC_SERVER_OPH_BV_07_I N/A
+TC_SERVER_OPH_BV_08_I N/A
+TC_SERVER_OPH_BV_09_I PASS
+TC_SERVER_OPH_BV_10_I PASS
+TC_SERVER_OPH_BV_11_I N/A
+TC_SERVER_OPH_BV_12_I N/A
+TC_SERVER_OPH_BV_13_I PASS
+TC_SERVER_OPH_BV_14_I PASS
+TC_SERVER_OPH_BV_15_I N/A
+TC_SERVER_OPH_BV_16_I N/A
+TC_SERVER_OPH_BV_17_I PASS
+TC_SERVER_OPH_BV_18_I PASS
+TC_SERVER_OPH_BV_19_I PASS
+TC_SERVER_OPH_BV_21_I N/A
+TC_SERVER_OPH_BV_22_I PASS
+TC_SERVER_OPH_BV_23_I PASS
+TC_SERVER_OPH_BV_24_I N/A
+TC_SERVER_OPH_BV_25_I N/A
+TC_SERVER_OPH_BV_26_I N/A
+TC_SERVER_ROB_BV_01_C PASS
+TC_SERVER_ROB_BV_02_C PASS
+TC_SERVER_SRM_BI_02_C N/A
+TC_SERVER_SRM_BI_03_C PASS
+TC_SERVER_SRM_BI_05_C N/A
+TC_SERVER_SRM_BV_04_C N/A
+TC_SERVER_SRM_BV_08_C N/A
+TC_SERVER_SRMP_BV_02_C N/A
+TC_SERVER_SRMP_BV_03_C N/A
+TC_CLIENT_OPH_BV_27_I N/A
+TC_CLIENT_OPH_BV_34_I PASS
+TC_SERVER_OPH_BV_27_I N/A
+TC_SERVER_OPH_BV_30_I PASS
+TC_SERVER_OPH_BV_31_I PASS
+TC_SERVER_OPH_BV_32_I PASS
+TC_SERVER_OPH_BV_33_I N/A
+TC_SERVER_OPH_BV_34_I PASS
+-------------------------------------------------------------------------------
diff --git a/doc/settings-storage.txt b/doc/settings-storage.txt
index 1839ba3f..a5f0edad 100644
--- a/doc/settings-storage.txt
+++ b/doc/settings-storage.txt
@@ -99,6 +99,7 @@ Sample:
LocalIrk=""
#endif
+
Attributes file format
======================
@@ -149,11 +150,15 @@ Cache directory file format
============================
Each file, named by remote device address, may includes multiple groups
-(General and ServiceRecords).
+(General, ServiceRecords, Attributes).
In ServiceRecords, SDP records are stored using their handle as key
(hexadecimal format).
+In "Attributes" group GATT database is stored using attribute handle as key
+(hexadecimal format). Value associated with this handle is serialized form of
+all data required to re-create given attribute. ":" is used to separate fields.
+
[General] group contains:
Name String Remote device friendly name
@@ -165,6 +170,37 @@ In ServiceRecords, SDP records are stored using their handle as key
<0x...> String SDP record as hexadecimal encoded
string
+In [Attributes] group value always starts with attribute type, that determines
+how to interpret rest of value:
+
+ Primary service:
+ 2800:end_handle:uuid
+
+ Secondary service:
+ 2801:end_handle:uuid
+
+ Included service:
+ 2802:start_handle:end_handle:uuid
+
+ Characteristic:
+ 2803:value_handle:properties:uuid
+
+ Descriptor:
+ uuid
+
+Sample Attributes section:
+ [Attributes]
+ 0001=2800:0005:1801
+ 0002=2803:0003:20:2a05
+ 0014=2800:001c:1800
+ 0015=2803:0016:02:2a00
+ 0017=2803:0018:02:2a01
+ 0019=2803:001a:02:2aa6
+ 0028=2800:ffff:0000180d-0000-1000-8000-00805f9b34fb
+ 0029=2803:002a:10:00002a37-0000-1000-8000-00805f9b34fb
+ 002b=2803:002c:02:00002a38-0000-1000-8000-00805f9b34fb
+ 002d=2803:002e:08:00002a39-0000-1000-8000-00805f9b34fb
+
Info file format
================
diff --git a/doc/supported-features.txt b/doc/supported-features.txt
index c7cd9fb8..33685d58 100644
--- a/doc/supported-features.txt
+++ b/doc/supported-features.txt
@@ -7,10 +7,11 @@ oFono or ConnMan.
Profile/protocol Version Role(s)
---------------------------------------------------------------------------
-GAP 4.0 (LE) Central, Observer, Broadcaster
-L2CAP 4.0 Server, Client
-SDP 4.0 Server, Client
-GATT 4.0 Server, Client
+GAP 4.2 (LE) Central, Peripheral,
+ Observer, Broadcaster
+L2CAP 4.2 Server, Client
+SDP 4.2 Server, Client
+GATT 4.2 Server, Client
SDAP 1.1 Server, Client
RFCOMM 1.1 Server, Client
SPP 1.1 Server, Client
diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 06253c66..5612ff06 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -1,4 +1,3 @@
-
BlueZ test coverage
*******************
@@ -29,10 +28,10 @@ test-gobex-header 28 OBEX header handling
test-gobex-apparam 18 OBEX apparam handling
test-gobex-transfer 36 OBEX transfer handling
test-gdbus-client 13 D-Bus client handling
-test-gatt 159 GATT qualification test cases
+test-gatt 180 GATT qualification test cases
test-hog 6 HID Over GATT qualification test cases
-----
- 740
+ 761
Automated end-to-end testing
@@ -40,15 +39,17 @@ Automated end-to-end testing
Application Count Description
-------------------------------------------
-mgmt-tester 293 Kernel management interface testing
-l2cap-tester 27 Kernel L2CAP implementation testing
+mgmt-tester 305 Kernel management interface testing
+l2cap-tester 33 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
-smp-tester 5 Kernel SMP implementation testing
+bnep-tester 1 Kernel BNEP implementation testing
+smp-tester 8 Kernel SMP implementation testing
sco-tester 8 Kernel SCO implementation testing
gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
+userchan-tester 3 Kernel HCI User Channel testting
-----
- 357
+ 382
Android end-to-end testing
diff --git a/doc/test-runner.txt b/doc/test-runner.txt
new file mode 100644
index 00000000..72e17ceb
--- /dev/null
+++ b/doc/test-runner.txt
@@ -0,0 +1,54 @@
+Notes for test-runner usage
+***************************
+
+
+Kernel configuration
+====================
+
+The test-runner tool requires a kernel that is at least build with these
+minimal options for a successful boot.
+
+ CONFIG_VIRTIO=y
+ CONFIG_VIRTIO_PCI=y
+
+ CONFIG_NET=y
+ CONFIG_INET=y
+
+ CONFIG_NET_9P=y
+ CONFIG_NET_9P_VIRTIO=y
+
+ CONFIG_9P_FS=y
+ CONFIG_9P_FS_POSIX_ACL=y
+
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
+ CONFIG_SERIAL_8250_PCI=y
+ CONFIG_SERIAL_8250_NR_UARTS=4
+
+ CONFIG_TMPFS=y
+ CONFIG_TMPFS_POSIX_ACL=y
+ CONFIG_TMPFS_XATTR=y
+
+ CONFIG_DEVTMPFS=y
+ CONFIG_DEBUG_FS=y
+
+These options should be installed as .config in the kernel source directory
+followed by this command.
+
+ make olddefconfig
+
+After that a default kernel with the required options can be built. More
+option (like the Bluetooth subsystem) can be enabled on top of this.
+
+Lock debuging
+-------------
+
+To catch locking related issues the following set of kernel config
+options may be useful:
+
+ CONFIG_LOCKDEP_SUPPORT=y
+ CONFIG_DEBUG_SPINLOCK=y
+ CONFIG_DEBUG_LOCK_ALLOC=y
+ CONFIG_PROVE_LOCKING=y
+ CONFIG_LOCKDEP=y
+ CONFIG_DEBUG_MUTEXES=y
diff --git a/emulator/btdev.c b/emulator/btdev.c
index 9642e866..38769d8f 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -32,9 +32,15 @@
#include <string.h>
#include <alloca.h>
#include <sys/uio.h>
+#include <stdint.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
#include "src/shared/util.h"
#include "src/shared/timeout.h"
+#include "src/shared/crypto.h"
+#include "src/shared/ecc.h"
#include "monitor/bt.h"
#include "btdev.h"
@@ -75,6 +81,8 @@ struct btdev {
struct hook *hook_list[MAX_HOOK_ENTRIES];
+ struct bt_crypto *crypto;
+
uint16_t manufacturer;
uint8_t version;
uint16_t revision;
@@ -113,6 +121,7 @@ struct btdev {
uint8_t simple_pairing_mode;
uint8_t ssp_debug_mode;
uint8_t secure_conn_support;
+ uint8_t host_flow_control;
uint8_t le_supported;
uint8_t le_simultaneous;
uint8_t le_event_mask[8];
@@ -131,6 +140,8 @@ struct btdev {
uint8_t le_adv_enable;
uint8_t le_ltk[16];
+ uint8_t le_local_sk256[32];
+
uint16_t sync_train_interval;
uint32_t sync_train_timeout;
uint8_t sync_train_service_data;
@@ -310,6 +321,7 @@ static void set_common_commands_bredrle(struct btdev *btdev)
{
btdev->commands[0] |= 0x20; /* Disconnect */
btdev->commands[2] |= 0x80; /* Read Remote Version Information */
+ btdev->commands[10] |= 0x20; /* Set Host Flow Control */
btdev->commands[10] |= 0x40; /* Host Buffer Size */
btdev->commands[15] |= 0x02; /* Read BD ADDR */
}
@@ -385,6 +397,7 @@ static void set_bredr_commands(struct btdev *btdev)
btdev->commands[18] |= 0x01; /* Read Inquiry Response TX Power */
btdev->commands[18] |= 0x02; /* Write Inquiry Response TX Power */
btdev->commands[18] |= 0x80; /* IO Capability Request Reply */
+ btdev->commands[20] |= 0x10; /* Read Encryption Key Size */
btdev->commands[23] |= 0x04; /* Read Data Block Size */
btdev->commands[29] |= 0x20; /* Read Local Supported Codecs */
btdev->commands[30] |= 0x08; /* Get MWS Transport Layer Config */
@@ -407,18 +420,36 @@ static void set_le_commands(struct btdev *btdev)
btdev->commands[25] |= 0x01; /* LE Set Event Mask */
btdev->commands[25] |= 0x02; /* LE Read Buffer Size */
btdev->commands[25] |= 0x04; /* LE Read Local Features */
+ btdev->commands[25] |= 0x10; /* LE Set Random Address */
btdev->commands[25] |= 0x20; /* LE Set Adv Parameters */
btdev->commands[25] |= 0x40; /* LE Read Adv TX Power */
btdev->commands[25] |= 0x80; /* LE Set Adv Data */
+ btdev->commands[26] |= 0x01; /* LE Set Scan Response Data */
btdev->commands[26] |= 0x02; /* LE Set Adv Enable */
btdev->commands[26] |= 0x04; /* LE Set Scan Parameters */
btdev->commands[26] |= 0x08; /* LE Set Scan Enable */
+ btdev->commands[26] |= 0x10; /* LE Create Connection */
btdev->commands[26] |= 0x40; /* LE Read White List Size */
+ btdev->commands[26] |= 0x80; /* LE Clear White List */
+ btdev->commands[27] |= 0x04; /* LE Connection Update */
+ btdev->commands[27] |= 0x20; /* LE Read Remote Used Features */
+ btdev->commands[27] |= 0x40; /* LE Encrypt */
btdev->commands[27] |= 0x80; /* LE Rand */
+ btdev->commands[28] |= 0x01; /* LE Start Encryption */
+ btdev->commands[28] |= 0x02; /* LE Long Term Key Request Reply */
+ btdev->commands[28] |= 0x04; /* LE Long Term Key Request Neg Reply */
btdev->commands[28] |= 0x08; /* LE Read Supported States */
btdev->commands[28] |= 0x10; /* LE Receiver Test */
btdev->commands[28] |= 0x20; /* LE Transmitter Test */
btdev->commands[28] |= 0x40; /* LE Test End */
+
+ /* Extra LE commands for >= 4.1 adapters */
+ btdev->commands[33] |= 0x10; /* LE Remote Conn Param Req Reply */
+ btdev->commands[33] |= 0x20; /* LE Remote Conn Param Req Neg Reply */
+
+ /* Extra LE commands for >= 4.2 adapters */
+ btdev->commands[34] |= 0x02; /* LE Read Local P-256 Public Key */
+ btdev->commands[34] |= 0x04; /* LE Generate DHKey */
}
static void set_bredrle_commands(struct btdev *btdev)
@@ -533,6 +564,10 @@ static void set_le_features(struct btdev *btdev)
btdev->features[4] |= 0x40; /* LE Supported */
btdev->max_page = 1;
+
+ btdev->le_features[0] |= 0x01; /* LE Encryption */
+ btdev->le_features[0] |= 0x02; /* Connection Parameters Request */
+ btdev->le_features[0] |= 0x08; /* Slave-initiated Features Exchange */
}
static void set_amp_features(struct btdev *btdev)
@@ -549,6 +584,15 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
return NULL;
memset(btdev, 0, sizeof(*btdev));
+
+ if (type == BTDEV_TYPE_BREDRLE || type == BTDEV_TYPE_LE) {
+ btdev->crypto = bt_crypto_new();
+ if (!btdev->crypto) {
+ free(btdev);
+ return NULL;
+ }
+ }
+
btdev->type = type;
btdev->manufacturer = 63;
@@ -576,7 +620,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
set_amp_commands(btdev);
break;
case BTDEV_TYPE_BREDR20:
- btdev->version = 0x04;
+ btdev->version = 0x03;
set_bredr20_features(btdev);
set_bredr20_commands(btdev);
break;
@@ -597,6 +641,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
index = add_btdev(btdev);
if (index < 0) {
+ bt_crypto_unref(btdev->crypto);
free(btdev);
return NULL;
}
@@ -614,6 +659,7 @@ void btdev_destroy(struct btdev *btdev)
if (btdev->inquiry_id > 0)
timeout_remove(btdev->inquiry_id);
+ bt_crypto_unref(btdev->crypto);
del_btdev(btdev);
free(btdev);
@@ -629,6 +675,16 @@ uint8_t *btdev_get_features(struct btdev *btdev)
return btdev->features;
}
+uint8_t btdev_get_scan_enable(struct btdev *btdev)
+{
+ return btdev->scan_enable;
+}
+
+uint8_t btdev_get_le_scan_enable(struct btdev *btdev)
+{
+ return btdev->le_scan_enable;
+}
+
static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
{
if (btdev1->auth_enable || btdev2->auth_enable)
@@ -752,6 +808,23 @@ static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
send_cmd(btdev, BT_HCI_EVT_CMD_STATUS, opcode, &iov, 1);
}
+static void le_meta_event(struct btdev *btdev, uint8_t event,
+ void *data, uint8_t len)
+{
+ void *pkt_data;
+
+ pkt_data = alloca(1 + len);
+ if (!pkt_data)
+ return;
+
+ ((uint8_t *) pkt_data)[0] = event;
+
+ if (len > 0)
+ memcpy(pkt_data + 1, data, len);
+
+ send_event(btdev, BT_HCI_EVT_LE_META_EVENT, pkt_data, 1 + len);
+}
+
static void num_completed_packets(struct btdev *btdev)
{
if (btdev->conn) {
@@ -1038,8 +1111,8 @@ static void sco_conn_complete(struct btdev *btdev, uint8_t status)
}
static void le_conn_complete(struct btdev *btdev,
- const uint8_t *bdaddr, uint8_t bdaddr_type,
- uint8_t status)
+ const struct bt_hci_cmd_le_create_conn *lecc,
+ uint8_t status)
{
char buf[1 + sizeof(struct bt_hci_evt_le_conn_complete)];
struct bt_hci_evt_le_conn_complete *cc = (void *) &buf[1];
@@ -1049,8 +1122,10 @@ static void le_conn_complete(struct btdev *btdev,
buf[0] = BT_HCI_EVT_LE_CONN_COMPLETE;
if (!status) {
- struct btdev *remote = find_btdev_by_bdaddr_type(bdaddr,
- bdaddr_type);
+ struct btdev *remote;
+
+ remote = find_btdev_by_bdaddr_type(lecc->peer_addr,
+ lecc->peer_addr_type);
btdev->conn = remote;
btdev->le_adv_enable = 0;
@@ -1066,15 +1141,16 @@ static void le_conn_complete(struct btdev *btdev,
cc->role = 0x01;
cc->handle = cpu_to_le16(42);
+ cc->interval = lecc->max_interval;
+ cc->latency = lecc->latency;
+ cc->supv_timeout = lecc->supv_timeout;
send_event(remote, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
-
- cc->handle = cpu_to_le16(42);
}
cc->status = status;
- cc->peer_addr_type = bdaddr_type;
- memcpy(cc->peer_addr, bdaddr, 6);
+ cc->peer_addr_type = lecc->peer_addr_type;
+ memcpy(cc->peer_addr, lecc->peer_addr, 6);
cc->role = 0x00;
send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
@@ -1116,16 +1192,17 @@ static bool adv_connectable(struct btdev *btdev)
return btdev->le_adv_type != 0x03;
}
-static void le_conn_request(struct btdev *btdev, const uint8_t *bdaddr,
- uint8_t bdaddr_type)
+static void le_conn_request(struct btdev *btdev,
+ const struct bt_hci_cmd_le_create_conn *lecc)
{
- struct btdev *remote = find_btdev_by_bdaddr_type(bdaddr, bdaddr_type);
+ struct btdev *remote = find_btdev_by_bdaddr_type(lecc->peer_addr,
+ lecc->peer_addr_type);
if (remote && adv_connectable(remote) && adv_match(btdev, remote) &&
- remote->le_adv_own_addr == bdaddr_type)
- le_conn_complete(btdev, bdaddr, bdaddr_type, 0);
+ remote->le_adv_own_addr == lecc->peer_addr_type)
+ le_conn_complete(btdev, lecc, 0);
else
- le_conn_complete(btdev, bdaddr, bdaddr_type,
+ le_conn_complete(btdev, lecc,
BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH);
}
@@ -1146,8 +1223,27 @@ static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
}
}
+static void rej_le_conn_update(struct btdev *btdev, uint16_t handle,
+ uint8_t reason)
+{
+ struct btdev *remote = btdev->conn;
+ struct __packed {
+ uint8_t subevent;
+ struct bt_hci_evt_le_conn_update_complete ev;
+ } ev;
+
+ if (!remote)
+ return;
+
+ ev.subevent = BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE;
+ ev.ev.handle = cpu_to_le16(handle);
+ ev.ev.status = cpu_to_le16(reason);
+
+ send_event(remote, BT_HCI_EVT_LE_META_EVENT, &ev, sizeof(ev));
+}
+
static void le_conn_update(struct btdev *btdev, uint16_t handle,
- uint16_t max_interval, uint16_t min_interval,
+ uint16_t min_interval, uint16_t max_interval,
uint16_t latency, uint16_t supv_timeout,
uint16_t min_length, uint16_t max_length)
{
@@ -1174,6 +1270,30 @@ static void le_conn_update(struct btdev *btdev, uint16_t handle,
send_event(remote, BT_HCI_EVT_LE_META_EVENT, &ev, sizeof(ev));
}
+static void le_conn_param_req(struct btdev *btdev, uint16_t handle,
+ uint16_t min_interval, uint16_t max_interval,
+ uint16_t latency, uint16_t supv_timeout,
+ uint16_t min_length, uint16_t max_length)
+{
+ struct btdev *remote = btdev->conn;
+ struct __packed {
+ uint8_t subevent;
+ struct bt_hci_evt_le_conn_param_request ev;
+ } ev;
+
+ if (!remote)
+ return;
+
+ ev.subevent = BT_HCI_EVT_LE_CONN_PARAM_REQUEST;
+ ev.ev.handle = cpu_to_le16(handle);
+ ev.ev.min_interval = cpu_to_le16(min_interval);
+ ev.ev.max_interval = cpu_to_le16(max_interval);
+ ev.ev.latency = cpu_to_le16(latency);
+ ev.ev.supv_timeout = cpu_to_le16(supv_timeout);
+
+ send_event(remote, BT_HCI_EVT_LE_META_EVENT, &ev, sizeof(ev));
+}
+
static void disconnect_complete(struct btdev *btdev, uint16_t handle,
uint8_t reason)
{
@@ -1547,6 +1667,24 @@ static void remote_clock_offset_complete(struct btdev *btdev, uint16_t handle)
&coc, sizeof(coc));
}
+static void read_enc_key_size_complete(struct btdev *btdev, uint16_t handle)
+{
+ struct bt_hci_rsp_read_encrypt_key_size rsp;
+
+ rsp.handle = cpu_to_le16(handle);
+
+ if (btdev->conn) {
+ rsp.status = BT_HCI_ERR_SUCCESS;
+ rsp.key_size = 16;
+ } else {
+ rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ rsp.key_size = 0;
+ }
+
+ cmd_complete(btdev, BT_HCI_CMD_READ_ENCRYPT_KEY_SIZE,
+ &rsp, sizeof(rsp));
+}
+
static void io_cap_req_reply_complete(struct btdev *btdev,
const uint8_t *bdaddr,
uint8_t capability, uint8_t oob_data,
@@ -1764,7 +1902,32 @@ static void le_set_scan_enable_complete(struct btdev *btdev)
}
}
-static void le_start_encrypt_complete(struct btdev *btdev)
+static void le_read_remote_features_complete(struct btdev *btdev)
+{
+ char buf[1 + sizeof(struct bt_hci_evt_le_remote_features_complete)];
+ struct bt_hci_evt_le_remote_features_complete *ev = (void *) &buf[1];
+ struct btdev *remote = btdev->conn;
+
+ if (!remote) {
+ cmd_status(btdev, BT_HCI_ERR_UNKNOWN_CONN_ID,
+ BT_HCI_CMD_LE_READ_REMOTE_FEATURES);
+ return;
+ }
+
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_READ_REMOTE_FEATURES);
+
+ memset(buf, 0, sizeof(buf));
+ buf[0] = BT_HCI_EVT_LE_REMOTE_FEATURES_COMPLETE;
+ ev->status = BT_HCI_ERR_SUCCESS;
+ ev->handle = cpu_to_le16(42);
+ memcpy(ev->features, remote->le_features, 8);
+
+ send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
+}
+
+static void le_start_encrypt_complete(struct btdev *btdev, uint16_t ediv,
+ uint64_t rand)
{
char buf[1 + sizeof(struct bt_hci_evt_le_long_term_key_request)];
struct bt_hci_evt_le_long_term_key_request *ev = (void *) &buf[1];
@@ -1781,6 +1944,8 @@ static void le_start_encrypt_complete(struct btdev *btdev)
memset(buf, 0, sizeof(buf));
buf[0] = BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST;
ev->handle = cpu_to_le16(42);
+ ev->ediv = ediv;
+ ev->rand = rand;
send_event(remote, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
}
@@ -1846,6 +2011,16 @@ static void ltk_neg_reply_complete(struct btdev *btdev)
send_event(remote, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev));
}
+static void btdev_reset(struct btdev *btdev)
+{
+ /* FIXME: include here clearing of all states that should be
+ * cleared upon HCI_Reset
+ */
+
+ btdev->le_scan_enable = 0x00;
+ btdev->le_adv_enable = 0x00;
+}
+
static void default_cmd(struct btdev *btdev, uint16_t opcode,
const void *data, uint8_t len)
{
@@ -1863,12 +2038,14 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
const struct bt_hci_cmd_write_auth_enable *wae;
const struct bt_hci_cmd_write_class_of_dev *wcod;
const struct bt_hci_cmd_write_voice_setting *wvs;
+ const struct bt_hci_cmd_set_host_flow_control *shfc;
const struct bt_hci_cmd_write_inquiry_mode *wim;
const struct bt_hci_cmd_write_afh_assessment_mode *waam;
const struct bt_hci_cmd_write_ext_inquiry_response *weir;
const struct bt_hci_cmd_write_simple_pairing_mode *wspm;
const struct bt_hci_cmd_io_capability_request_reply *icrr;
const struct bt_hci_cmd_io_capability_request_reply *icrnr;
+ const struct bt_hci_cmd_read_encrypt_key_size *reks;
const struct bt_hci_cmd_write_le_host_supported *wlhs;
const struct bt_hci_cmd_write_secure_conn_support *wscs;
const struct bt_hci_cmd_set_event_mask_page2 *semp2;
@@ -1884,6 +2061,10 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
const struct bt_hci_cmd_le_set_scan_enable *lsse;
const struct bt_hci_cmd_le_start_encrypt *lse;
const struct bt_hci_cmd_le_ltk_req_reply *llrr;
+ const struct bt_hci_cmd_le_encrypt *lenc_cmd;
+ const struct bt_hci_cmd_le_generate_dhkey *dh;
+ const struct bt_hci_cmd_le_conn_param_req_reply *lcprr_cmd;
+ const struct bt_hci_cmd_le_conn_param_req_neg_reply *lcprnr_cmd;
const struct bt_hci_cmd_read_local_amp_assoc *rlaa_cmd;
const struct bt_hci_cmd_read_rssi *rrssi;
const struct bt_hci_cmd_read_tx_power *rtxp;
@@ -1925,11 +2106,14 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
struct bt_hci_rsp_read_local_amp_info rlai;
struct bt_hci_rsp_read_local_amp_assoc rlaa_rsp;
struct bt_hci_rsp_get_mws_transport_config *gmtc;
+ struct bt_hci_rsp_le_conn_param_req_reply lcprr_rsp;
+ struct bt_hci_rsp_le_conn_param_req_neg_reply lcprnr_rsp;
struct bt_hci_rsp_le_read_buffer_size lrbs;
struct bt_hci_rsp_le_read_local_features lrlf;
struct bt_hci_rsp_le_read_adv_tx_power lratp;
struct bt_hci_rsp_le_read_supported_states lrss;
struct bt_hci_rsp_le_read_white_list_size lrwls;
+ struct bt_hci_rsp_le_encrypt lenc;
struct bt_hci_rsp_le_rand lr;
struct bt_hci_rsp_le_test_end lte;
struct bt_hci_rsp_remote_name_request_cancel rnrc_rsp;
@@ -1941,6 +2125,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
struct bt_hci_rsp_user_confirm_request_neg_reply ucrnr_rsp;
struct bt_hci_rsp_read_rssi rrssi_rsp;
struct bt_hci_rsp_read_tx_power rtxp_rsp;
+ struct bt_hci_evt_le_read_local_pk256_complete pk_evt;
+ struct bt_hci_evt_le_generate_dhkey_complete dh_evt;
uint8_t status, page;
switch (opcode) {
@@ -2090,6 +2276,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
break;
case BT_HCI_CMD_RESET:
+ btdev_reset(btdev);
status = BT_HCI_ERR_SUCCESS;
cmd_complete(btdev, opcode, &status, sizeof(status));
break;
@@ -2302,11 +2489,28 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &status, sizeof(status));
break;
+ case BT_HCI_CMD_SET_HOST_FLOW_CONTROL:
+ shfc = data;
+ if (shfc->enable > 0x03) {
+ status = BT_HCI_ERR_INVALID_PARAMETERS;
+ } else {
+ btdev->host_flow_control = shfc->enable;
+ status = BT_HCI_ERR_SUCCESS;
+ }
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
case BT_HCI_CMD_HOST_BUFFER_SIZE:
status = BT_HCI_ERR_SUCCESS;
cmd_complete(btdev, opcode, &status, sizeof(status));
break;
+ case BT_HCI_CMD_HOST_NUM_COMPLETED_PACKETS:
+ /* This command is special in the sense that no event is
+ * normally generated after the command has completed.
+ */
+ break;
+
case BT_HCI_CMD_READ_NUM_SUPPORTED_IAC:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
@@ -2648,6 +2852,14 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &rtxp_rsp, sizeof(rtxp_rsp));
break;
+ case BT_HCI_CMD_READ_ENCRYPT_KEY_SIZE:
+ if (btdev->type != BTDEV_TYPE_BREDRLE &&
+ btdev->type != BTDEV_TYPE_BREDR)
+ goto unsupported;
+ reks = data;
+ read_enc_key_size_complete(btdev, le16_to_cpu(reks->handle));
+ break;
+
case BT_HCI_CMD_READ_LOCAL_AMP_INFO:
if (btdev->type != BTDEV_TYPE_AMP)
goto unsupported;
@@ -2803,8 +3015,6 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
status = BT_HCI_ERR_SUCCESS;
}
cmd_complete(btdev, opcode, &status, sizeof(status));
- if (status == BT_HCI_ERR_SUCCESS && btdev->le_scan_enable)
- le_set_scan_enable_complete(btdev);
break;
case BT_HCI_CMD_LE_CREATE_CONN:
@@ -2834,6 +3044,64 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &status, sizeof(status));
break;
+ case BT_HCI_CMD_LE_ENCRYPT:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ lenc_cmd = data;
+ if (!bt_crypto_e(btdev->crypto, lenc_cmd->key,
+ lenc_cmd->plaintext, lenc.data)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ lenc.status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &lenc, sizeof(lenc));
+ break;
+
+ case BT_HCI_CMD_LE_RAND:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ if (!bt_crypto_random_bytes(btdev->crypto,
+ (uint8_t *)&lr.number, 8)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ lr.status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &lr, sizeof(lr));
+ break;
+
+ case BT_HCI_CMD_LE_READ_LOCAL_PK256:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ if (!ecc_make_key(pk_evt.local_pk256, btdev->le_local_sk256)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_READ_LOCAL_PK256);
+ pk_evt.status = BT_HCI_ERR_SUCCESS;
+ le_meta_event(btdev, BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE,
+ &pk_evt, sizeof(pk_evt));
+ break;
+
+ case BT_HCI_CMD_LE_GENERATE_DHKEY:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ dh = data;
+ if (!ecdh_shared_secret(dh->remote_pk256, btdev->le_local_sk256,
+ dh_evt.dhkey)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_GENERATE_DHKEY);
+ le_meta_event(btdev, BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE,
+ &dh_evt, sizeof(dh_evt));
+ break;
+
case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
@@ -2862,12 +3130,10 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &status, sizeof(status));
break;
- case BT_HCI_CMD_LE_RAND:
+ case BT_HCI_CMD_LE_READ_REMOTE_FEATURES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
- lr.status = BT_HCI_ERR_SUCCESS;
- lr.number = rand();
- cmd_complete(btdev, opcode, &lr, sizeof(lr));
+ le_read_remote_features_complete(btdev);
break;
case BT_HCI_CMD_LE_START_ENCRYPT:
@@ -2875,7 +3141,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
goto unsupported;
lse = data;
memcpy(btdev->le_ltk, lse->ltk, 16);
- le_start_encrypt_complete(btdev);
+ le_start_encrypt_complete(btdev, lse->ediv, lse->rand);
break;
case BT_HCI_CMD_LE_LTK_REQ_REPLY:
@@ -2944,6 +3210,22 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &lte, sizeof(lte));
break;
+ case BT_HCI_CMD_LE_CONN_PARAM_REQ_REPLY:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ lcprr_cmd = data;
+ lcprr_rsp.handle = lcprr_cmd->handle;
+ lcprr_rsp.status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &lcprr_rsp, sizeof(lcprr_rsp));
+ break;
+ case BT_HCI_CMD_LE_CONN_PARAM_REQ_NEG_REPLY:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ lcprnr_cmd = data;
+ lcprnr_rsp.handle = lcprnr_cmd->handle;
+ lcprnr_rsp.status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &lcprnr_rsp, sizeof(lcprnr_rsp));
+ break;
default:
goto unsupported;
}
@@ -2978,6 +3260,9 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode,
const struct bt_hci_cmd_read_clock_offset *rco;
const struct bt_hci_cmd_le_create_conn *lecc;
const struct bt_hci_cmd_le_conn_update *lecu;
+ const struct bt_hci_cmd_le_conn_param_req_reply *lcprr;
+ const struct bt_hci_cmd_le_conn_param_req_neg_reply *lcprnr;
+ const struct bt_hci_cmd_le_set_scan_enable *lsse;
switch (opcode) {
case BT_HCI_CMD_INQUIRY:
@@ -3122,21 +3407,57 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode,
return;
lecc = data;
btdev->le_scan_own_addr_type = lecc->own_addr_type;
- le_conn_request(btdev, lecc->peer_addr, lecc->peer_addr_type);
+ le_conn_request(btdev, lecc);
break;
case BT_HCI_CMD_LE_CONN_UPDATE:
if (btdev->type == BTDEV_TYPE_BREDR)
return;
lecu = data;
- le_conn_update(btdev, le16_to_cpu(lecu->handle),
- le16_to_cpu(lecu->min_interval),
- le16_to_cpu(lecu->max_interval),
- le16_to_cpu(lecu->latency),
- le16_to_cpu(lecu->supv_timeout),
- le16_to_cpu(lecu->min_length),
- le16_to_cpu(lecu->max_length));
+ if (btdev->le_features[0] & 0x02)
+ le_conn_param_req(btdev, le16_to_cpu(lecu->handle),
+ le16_to_cpu(lecu->min_interval),
+ le16_to_cpu(lecu->max_interval),
+ le16_to_cpu(lecu->latency),
+ le16_to_cpu(lecu->supv_timeout),
+ le16_to_cpu(lecu->min_length),
+ le16_to_cpu(lecu->max_length));
+ else
+ le_conn_update(btdev, le16_to_cpu(lecu->handle),
+ le16_to_cpu(lecu->min_interval),
+ le16_to_cpu(lecu->max_interval),
+ le16_to_cpu(lecu->latency),
+ le16_to_cpu(lecu->supv_timeout),
+ le16_to_cpu(lecu->min_length),
+ le16_to_cpu(lecu->max_length));
+ break;
+ case BT_HCI_CMD_LE_CONN_PARAM_REQ_REPLY:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ return;
+ lcprr = data;
+ le_conn_update(btdev, le16_to_cpu(lcprr->handle),
+ le16_to_cpu(lcprr->min_interval),
+ le16_to_cpu(lcprr->max_interval),
+ le16_to_cpu(lcprr->latency),
+ le16_to_cpu(lcprr->supv_timeout),
+ le16_to_cpu(lcprr->min_length),
+ le16_to_cpu(lcprr->max_length));
+ break;
+ case BT_HCI_CMD_LE_CONN_PARAM_REQ_NEG_REPLY:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ return;
+ lcprnr = data;
+ rej_le_conn_update(btdev, le16_to_cpu(lcprnr->handle),
+ le16_to_cpu(lcprnr->reason));
break;
+ break;
+ case BT_HCI_CMD_LE_SET_SCAN_ENABLE:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ return;
+ lsse = data;
+ if (btdev->le_scan_enable && lsse->enable)
+ le_set_scan_enable_complete(btdev);
+
}
}
@@ -3220,10 +3541,34 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
}
}
+static void send_acl(struct btdev *conn, const void *data, uint16_t len)
+{
+ struct bt_hci_acl_hdr hdr;
+ struct iovec iov[3];
+
+ /* Packet type */
+ iov[0].iov_base = (void *) data;
+ iov[0].iov_len = 1;
+
+ /* ACL_START_NO_FLUSH is only allowed from host to controller.
+ * From controller to host this should be converted to ACL_START.
+ */
+ memcpy(&hdr, data + 1, sizeof(hdr));
+ if (acl_flags(hdr.handle) == ACL_START_NO_FLUSH)
+ hdr.handle = acl_handle_pack(acl_handle(hdr.handle), ACL_START);
+
+ iov[1].iov_base = &hdr;
+ iov[1].iov_len = sizeof(hdr);
+
+ iov[2].iov_base = (void *) (data + 1 + sizeof(hdr));
+ iov[2].iov_len = len - 1 - sizeof(hdr);
+
+ send_packet(conn, iov, 3);
+}
+
void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
{
uint8_t pkt_type;
- struct iovec iov;
if (!btdev)
return;
@@ -3238,11 +3583,8 @@ void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
process_cmd(btdev, data + 1, len - 1);
break;
case BT_H4_ACL_PKT:
- if (btdev->conn) {
- iov.iov_base = (void *) data;
- iov.iov_len = len;
- send_packet(btdev->conn, &iov, 1);
- }
+ if (btdev->conn)
+ send_acl(btdev->conn, data, len);
num_completed_packets(btdev);
break;
default:
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 4b724a7b..40c72199 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -80,6 +80,10 @@ void btdev_destroy(struct btdev *btdev);
const uint8_t *btdev_get_bdaddr(struct btdev *btdev);
uint8_t *btdev_get_features(struct btdev *btdev);
+uint8_t btdev_get_scan_enable(struct btdev *btdev);
+
+uint8_t btdev_get_le_scan_enable(struct btdev *btdev);
+
void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
void *user_data);
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 16e103d1..3638fe45 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -1161,6 +1161,30 @@ static void evt_le_conn_complete(struct bthost *bthost, const void *data,
init_conn(bthost, le16_to_cpu(ev->handle), ev->peer_addr, addr_type);
}
+static void evt_le_conn_update_complete(struct bthost *bthost, const void *data,
+ uint8_t len)
+{
+ const struct bt_hci_evt_le_conn_update_complete *ev = data;
+
+ if (len < sizeof(*ev))
+ return;
+
+ if (ev->status)
+ return;
+}
+
+static void evt_le_remote_features_complete(struct bthost *bthost,
+ const void *data, uint8_t len)
+{
+ const struct bt_hci_evt_le_remote_features_complete *ev = data;
+
+ if (len < sizeof(*ev))
+ return;
+
+ if (ev->status)
+ return;
+}
+
static void evt_le_ltk_request(struct bthost *bthost, const void *data,
uint8_t len)
{
@@ -1207,6 +1231,12 @@ static void evt_le_meta_event(struct bthost *bthost, const void *data,
case BT_HCI_EVT_LE_CONN_COMPLETE:
evt_le_conn_complete(bthost, evt_data, len - 1);
break;
+ case BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE:
+ evt_le_conn_update_complete(bthost, evt_data, len - 1);
+ break;
+ case BT_HCI_EVT_LE_REMOTE_FEATURES_COMPLETE:
+ evt_le_remote_features_complete(bthost, evt_data, len - 1);
+ break;
case BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST:
evt_le_ltk_request(bthost, evt_data, len - 1);
break;
@@ -2228,6 +2258,12 @@ void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr,
if (addr_type == BDADDR_LE_RANDOM)
cc.peer_addr_type = 0x01;
+ cc.scan_interval = cpu_to_le16(0x0060);
+ cc.scan_window = cpu_to_le16(0x0030);
+ cc.min_interval = cpu_to_le16(0x0028);
+ cc.max_interval = cpu_to_le16(0x0038);
+ cc.supv_timeout = cpu_to_le16(0x002a);
+
send_command(bthost, BT_HCI_CMD_LE_CREATE_CONN,
&cc, sizeof(cc));
}
@@ -2249,30 +2285,29 @@ void bthost_write_scan_enable(struct bthost *bthost, uint8_t scan)
send_command(bthost, BT_HCI_CMD_WRITE_SCAN_ENABLE, &scan, 1);
}
-void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable, uint8_t flags)
+void bthost_set_adv_data(struct bthost *bthost, const uint8_t *data,
+ uint8_t len)
{
- struct bt_hci_cmd_le_set_adv_parameters cp;
-
- memset(&cp, 0, sizeof(cp));
- send_command(bthost, BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
- &cp, sizeof(cp));
+ struct bt_hci_cmd_le_set_adv_data adv_cp;
- if (flags) {
- struct bt_hci_cmd_le_set_adv_data adv_cp;
+ memset(adv_cp.data, 0, 31);
- memset(adv_cp.data, 0, 31);
-
- adv_cp.data[0] = 0x02; /* Field length */
- adv_cp.data[1] = 0x01; /* Flags */
- adv_cp.data[2] = flags;
+ if (len) {
+ adv_cp.len = len;
+ memcpy(adv_cp.data, data, len);
+ }
- adv_cp.data[3] = 0x00; /* Field terminator */
+ send_command(bthost, BT_HCI_CMD_LE_SET_ADV_DATA, &adv_cp,
+ sizeof(adv_cp));
+}
- adv_cp.len = 1 + adv_cp.data[0];
+void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable)
+{
+ struct bt_hci_cmd_le_set_adv_parameters cp;
- send_command(bthost, BT_HCI_CMD_LE_SET_ADV_DATA, &adv_cp,
- sizeof(adv_cp));
- }
+ memset(&cp, 0, sizeof(cp));
+ send_command(bthost, BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+ &cp, sizeof(cp));
send_command(bthost, BT_HCI_CMD_LE_SET_ADV_ENABLE, &enable, 1);
}
diff --git a/emulator/bthost.h b/emulator/bthost.h
index 6beb1f48..7110db81 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -79,8 +79,9 @@ bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t req,
void bthost_write_scan_enable(struct bthost *bthost, uint8_t scan);
-void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable,
- uint8_t flags);
+void bthost_set_adv_data(struct bthost *bthost, const uint8_t *data,
+ uint8_t len);
+void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable);
void bthost_write_ssp_mode(struct bthost *bthost, uint8_t mode);
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 4881a249..6a534990 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -427,6 +427,22 @@ const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu)
return btdev_get_bdaddr(hciemu->client_dev);
}
+uint8_t hciemu_get_master_scan_enable(struct hciemu *hciemu)
+{
+ if (!hciemu || !hciemu->master_dev)
+ return 0;
+
+ return btdev_get_scan_enable(hciemu->master_dev);
+}
+
+uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu)
+{
+ if (!hciemu || !hciemu->master_dev)
+ return 0;
+
+ return btdev_get_le_scan_enable(hciemu->master_dev);
+}
+
bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
hciemu_command_func_t function, void *user_data)
{
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 41ca3fce..c5578d13 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -53,6 +53,10 @@ uint8_t *hciemu_get_features(struct hciemu *hciemu);
const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu);
const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
+uint8_t hciemu_get_master_scan_enable(struct hciemu *hciemu);
+
+uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu);
+
typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
uint8_t len, void *user_data);
diff --git a/emulator/le.c b/emulator/le.c
index dc51469c..82ae573f 100644
--- a/emulator/le.c
+++ b/emulator/le.c
@@ -33,6 +33,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
+#include <time.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
@@ -68,6 +69,9 @@ struct bt_le {
struct bt_phy *phy;
struct bt_crypto *crypto;
int adv_timeout_id;
+ int scan_timeout_id;
+ bool scan_window_active;
+ uint8_t scan_chan_idx;
uint8_t event_mask[16];
uint16_t manufacturer;
@@ -421,11 +425,12 @@ static void send_event(struct bt_le *hci, uint8_t event,
fprintf(stderr, "Write to /dev/vhci failed (%m)\n");
}
-static void send_adv_pkt(struct bt_le *hci)
+static void send_adv_pkt(struct bt_le *hci, uint8_t channel)
{
struct bt_phy_pkt_adv pkt;
memset(&pkt, 0, sizeof(pkt));
+ pkt.chan_idx = channel;
pkt.pdu_type = hci->le_adv_type;
pkt.tx_addr_type = hci->le_adv_own_addr_type;
switch (hci->le_adv_own_addr_type) {
@@ -448,17 +453,33 @@ static void send_adv_pkt(struct bt_le *hci)
hci->le_scan_rsp_data, pkt.scan_rsp_len);
}
+static unsigned int get_adv_delay(void)
+{
+ /* The advertising delay is a pseudo-random value with a range
+ * of 0 ms to 10 ms generated for each advertising event.
+ */
+ srand(time(NULL));
+ return (rand() % 11);
+}
+
static void adv_timeout_callback(int id, void *user_data)
{
struct bt_le *hci = user_data;
- unsigned int min_msec, max_msec;
+ unsigned int msec, min_msec, max_msec;
- send_adv_pkt(hci);
+ if (hci->le_adv_channel_map & 0x01)
+ send_adv_pkt(hci, 37);
+ if (hci->le_adv_channel_map & 0x02)
+ send_adv_pkt(hci, 38);
+ if (hci->le_adv_channel_map & 0x04)
+ send_adv_pkt(hci, 39);
min_msec = (hci->le_adv_min_interval * 625) / 1000;
max_msec = (hci->le_adv_max_interval * 625) / 1000;
- if (mainloop_modify_timeout(id, (min_msec + max_msec) / 2) < 0) {
+ msec = ((min_msec + max_msec) / 2) + get_adv_delay();
+
+ if (mainloop_modify_timeout(id, msec) < 0) {
fprintf(stderr, "Setting advertising timeout failed\n");
hci->le_adv_enable = 0x00;
}
@@ -471,7 +492,7 @@ static bool start_adv(struct bt_le *hci)
if (hci->adv_timeout_id >= 0)
return false;
- msec = (hci->le_adv_min_interval * 625) / 1000;
+ msec = ((hci->le_adv_min_interval * 625) / 1000) + get_adv_delay();
hci->adv_timeout_id = mainloop_add_timeout(msec, adv_timeout_callback,
hci, NULL);
@@ -492,6 +513,65 @@ static bool stop_adv(struct bt_le *hci)
return true;
}
+static void scan_timeout_callback(int id, void *user_data)
+{
+ struct bt_le *hci = user_data;
+ unsigned int msec;
+
+ if (hci->le_scan_window == hci->le_scan_interval ||
+ !hci->scan_window_active) {
+ msec = (hci->le_scan_window * 625) / 1000;
+ hci->scan_window_active = true;
+
+ hci->scan_chan_idx++;
+ if (hci->scan_chan_idx > 39)
+ hci->scan_chan_idx = 37;
+ } else {
+ msec = ((hci->le_scan_interval -
+ hci->le_scan_window) * 625) / 1000;
+ hci->scan_window_active = false;
+ }
+
+ if (mainloop_modify_timeout(id, msec) < 0) {
+ fprintf(stderr, "Setting scanning timeout failed\n");
+ hci->le_scan_enable = 0x00;
+ hci->scan_window_active = false;
+ }
+}
+
+static bool start_scan(struct bt_le *hci)
+{
+ unsigned int msec;
+
+ if (hci->scan_timeout_id >= 0)
+ return false;
+
+ msec = (hci->le_scan_window * 625) / 1000;
+
+ hci->scan_timeout_id = mainloop_add_timeout(msec, scan_timeout_callback,
+ hci, NULL);
+ if (hci->scan_timeout_id < 0)
+ return false;
+
+ hci->scan_window_active = true;
+ hci->scan_chan_idx = 37;
+
+ return true;
+}
+
+static bool stop_scan(struct bt_le *hci)
+{
+ if (hci->scan_timeout_id < 0)
+ return false;
+
+ mainloop_remove_timeout(hci->scan_timeout_id);
+ hci->scan_timeout_id = -1;
+
+ hci->scan_window_active = false;
+
+ return true;
+}
+
static void cmd_complete(struct bt_le *hci, uint16_t opcode,
const void *data, uint8_t len)
{
@@ -565,6 +645,7 @@ static void cmd_reset(struct bt_le *hci, const void *data, uint8_t size)
uint8_t status;
stop_adv(hci);
+ stop_scan(hci);
reset_defaults(hci);
status = BT_HCI_ERR_SUCCESS;
@@ -970,6 +1051,7 @@ static void cmd_le_set_scan_enable(struct bt_le *hci,
{
const struct bt_hci_cmd_le_set_scan_enable *cmd = data;
uint8_t status;
+ bool result;
/* Valid range for scan enable is 0x00 to 0x01 */
if (cmd->enable > 0x01) {
@@ -993,6 +1075,17 @@ static void cmd_le_set_scan_enable(struct bt_le *hci,
clear_scan_cache(hci);
+ if (cmd->enable == 0x01)
+ result = start_scan(hci);
+ else
+ result = stop_scan(hci);
+
+ if (!result) {
+ cmd_status(hci, BT_HCI_ERR_UNSPECIFIED_ERROR,
+ BT_HCI_CMD_LE_SET_SCAN_ENABLE);
+ return;
+ }
+
hci->le_scan_enable = cmd->enable;
hci->le_scan_filter_dup = cmd->filter_dup;
@@ -1709,12 +1802,15 @@ static void phy_recv_callback(uint16_t type, const void *data,
if (!(hci->le_event_mask[0] & 0x02))
return;
- if (hci->le_scan_enable == 0x01) {
+ if (hci->scan_window_active) {
const struct bt_phy_pkt_adv *pkt = data;
uint8_t buf[100];
struct bt_hci_evt_le_adv_report *evt = (void *) buf;
uint8_t tx_addr_type, tx_addr[6];
+ if (hci->scan_chan_idx != pkt->chan_idx)
+ break;
+
resolve_peer_addr(hci, pkt->tx_addr_type, pkt->tx_addr,
&tx_addr_type, tx_addr);
@@ -1773,6 +1869,8 @@ struct bt_le *bt_le_new(void)
return NULL;
hci->adv_timeout_id = -1;
+ hci->scan_timeout_id = -1;
+ hci->scan_window_active = false;
reset_defaults(hci);
diff --git a/emulator/phy.h b/emulator/phy.h
index 9abfd689..d5efa518 100644
--- a/emulator/phy.h
+++ b/emulator/phy.h
@@ -49,6 +49,7 @@ bool bt_phy_register(struct bt_phy *phy, bt_phy_callback_func_t callback,
#define BT_PHY_PKT_ADV 0x0001
struct bt_phy_pkt_adv {
+ uint8_t chan_idx;
uint8_t pdu_type;
uint8_t tx_addr_type;
uint8_t tx_addr[6];
@@ -60,6 +61,7 @@ struct bt_phy_pkt_adv {
#define BT_PHY_PKT_CONN 0x0002
struct bt_phy_pkt_conn {
+ uint8_t chan_idx;
uint8_t link_type;
uint8_t tx_addr_type;
uint8_t tx_addr[6];
diff --git a/emulator/server.c b/emulator/server.c
index 76998d9f..c28b15eb 100644
--- a/emulator/server.c
+++ b/emulator/server.c
@@ -130,6 +130,7 @@ again:
while (count > 0) {
hci_command_hdr *cmd_hdr;
+ hci_acl_hdr *acl_hdr;
if (!client->pkt_data) {
client->pkt_type = ptr[0];
@@ -146,6 +147,12 @@ again:
client->pkt_data = malloc(client->pkt_expect);
client->pkt_len = 0;
break;
+ case HCI_ACLDATA_PKT:
+ acl_hdr = (hci_acl_hdr*)(ptr + 1);
+ client->pkt_expect = HCI_ACL_HDR_SIZE + acl_hdr->dlen + 1;
+ client->pkt_data = malloc(client->pkt_expect);
+ client->pkt_len = 0;
+ break;
default:
printf("packet error\n");
return;
diff --git a/gdbus/client.c b/gdbus/client.c
index 48711ae8..068e778c 100644
--- a/gdbus/client.c
+++ b/gdbus/client.c
@@ -1073,9 +1073,6 @@ static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
dbus_message_iter_next(&dict);
}
-
- if (client->ready)
- client->ready(client, client->ready_data);
}
static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
@@ -1096,6 +1093,9 @@ static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
parse_managed_objects(client, reply);
done:
+ if (client->ready)
+ client->ready(client, client->ready_data);
+
dbus_message_unref(reply);
dbus_pending_call_unref(client->get_objects_call);
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index ffb12cb7..54ab0f42 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -31,11 +31,6 @@ extern "C" {
#include <dbus/dbus.h>
#include <glib.h>
-typedef enum GDBusMethodFlags GDBusMethodFlags;
-typedef enum GDBusSignalFlags GDBusSignalFlags;
-typedef enum GDBusPropertyFlags GDBusPropertyFlags;
-typedef enum GDBusSecurityFlags GDBusSecurityFlags;
-
typedef struct GDBusArgInfo GDBusArgInfo;
typedef struct GDBusMethodTable GDBusMethodTable;
typedef struct GDBusSignalTable GDBusSignalTable;
@@ -115,6 +110,16 @@ enum GDBusSecurityFlags {
G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION = (1 << 2),
};
+enum GDbusPropertyChangedFlags {
+ G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH = (1 << 0),
+};
+
+typedef enum GDBusMethodFlags GDBusMethodFlags;
+typedef enum GDBusSignalFlags GDBusSignalFlags;
+typedef enum GDBusPropertyFlags GDBusPropertyFlags;
+typedef enum GDBusSecurityFlags GDBusSecurityFlags;
+typedef enum GDbusPropertyChangedFlags GDbusPropertyChangedFlags;
+
struct GDBusArgInfo {
const char *name;
const char *signature;
@@ -216,6 +221,7 @@ struct GDBusSecurityTable {
.flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
void g_dbus_set_flags(int flags);
+int g_dbus_get_flags(void);
gboolean g_dbus_register_interface(DBusConnection *connection,
const char *path, const char *name,
@@ -305,6 +311,10 @@ void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
void g_dbus_emit_property_changed(DBusConnection *connection,
const char *path, const char *interface,
const char *name);
+void g_dbus_emit_property_changed_full(DBusConnection *connection,
+ const char *path, const char *interface,
+ const char *name,
+ GDbusPropertyChangedFlags flags);
gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
const char *interface, DBusMessageIter *iter);
diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c
index 3e88eac8..b90a8447 100644
--- a/gdbus/mainloop.c
+++ b/gdbus/mainloop.c
@@ -322,6 +322,7 @@ DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
return NULL;
if (setup_bus(conn, name, error) == FALSE) {
+ dbus_connection_close(conn);
dbus_connection_unref(conn);
return NULL;
}
diff --git a/gdbus/object.c b/gdbus/object.c
index 94f074a0..1ae45d6f 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -281,7 +281,8 @@ static DBusHandlerResult process_message(DBusConnection *connection,
reply = method->function(connection, message, iface_user_data);
- if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
+ if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY ||
+ dbus_message_get_no_reply(message)) {
if (reply != NULL)
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
@@ -1479,7 +1480,10 @@ DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
{
char str[1024];
- vsnprintf(str, sizeof(str), format, args);
+ if (format)
+ vsnprintf(str, sizeof(str), format, args);
+ else
+ str[0] = '\0';
return dbus_message_new_error(message, name, str);
}
@@ -1597,11 +1601,8 @@ gboolean g_dbus_send_error_valist(DBusConnection *connection,
const char *format, va_list args)
{
DBusMessage *error;
- char str[1024];
- vsnprintf(str, sizeof(str), format, args);
-
- error = dbus_message_new_error(message, name, str);
+ error = g_dbus_create_error_valist(message, name, format, args);
if (error == NULL)
return FALSE;
@@ -1846,9 +1847,10 @@ static void process_property_changes(struct generic_data *data)
}
}
-void g_dbus_emit_property_changed(DBusConnection *connection,
+void g_dbus_emit_property_changed_full(DBusConnection *connection,
const char *path, const char *interface,
- const char *name)
+ const char *name,
+ GDbusPropertyChangedFlags flags)
{
const GDBusPropertyTable *property;
struct generic_data *data;
@@ -1886,7 +1888,16 @@ void g_dbus_emit_property_changed(DBusConnection *connection,
iface->pending_prop = g_slist_prepend(iface->pending_prop,
(void *) property);
- add_pending(data);
+ if (flags & G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH)
+ process_property_changes(data);
+ else
+ add_pending(data);
+}
+
+void g_dbus_emit_property_changed(DBusConnection *connection, const char *path,
+ const char *interface, const char *name)
+{
+ g_dbus_emit_property_changed_full(connection, path, interface, name, 0);
}
gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
@@ -1942,3 +1953,8 @@ void g_dbus_set_flags(int flags)
{
global_flags = flags;
}
+
+int g_dbus_get_flags(void)
+{
+ return global_flags;
+}
diff --git a/gdbus/watch.c b/gdbus/watch.c
index b60f650f..447e4867 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -204,6 +204,30 @@ static gboolean remove_match(struct filter_data *data)
return TRUE;
}
+static void filter_data_free(struct filter_data *data)
+{
+ GSList *l;
+
+ /* Remove filter if there are no listeners left for the connection */
+ if (filter_data_find(data->connection) == NULL)
+ dbus_connection_remove_filter(data->connection, message_filter,
+ NULL);
+
+ for (l = data->callbacks; l != NULL; l = l->next)
+ g_free(l->data);
+
+ g_slist_free(data->callbacks);
+ g_dbus_remove_watch(data->connection, data->name_watch);
+ g_free(data->name);
+ g_free(data->owner);
+ g_free(data->path);
+ g_free(data->interface);
+ g_free(data->member);
+ g_free(data->argument);
+ dbus_connection_unref(data->connection);
+ g_free(data);
+}
+
static struct filter_data *filter_data_get(DBusConnection *connection,
DBusHandleMessageFunction filter,
const char *sender,
@@ -248,7 +272,7 @@ proceed:
data->argument = g_strdup(argument);
if (!add_match(data, filter)) {
- g_free(data);
+ filter_data_free(data);
return NULL;
}
@@ -277,30 +301,6 @@ static struct filter_callback *filter_data_find_callback(
return NULL;
}
-static void filter_data_free(struct filter_data *data)
-{
- GSList *l;
-
- /* Remove filter if there are no listeners left for the connection */
- if (filter_data_find(data->connection) == NULL)
- dbus_connection_remove_filter(data->connection, message_filter,
- NULL);
-
- for (l = data->callbacks; l != NULL; l = l->next)
- g_free(l->data);
-
- g_slist_free(data->callbacks);
- g_dbus_remove_watch(data->connection, data->name_watch);
- g_free(data->name);
- g_free(data->owner);
- g_free(data->path);
- g_free(data->interface);
- g_free(data->member);
- g_free(data->argument);
- dbus_connection_unref(data->connection);
- g_free(data);
-}
-
static void filter_data_call_and_free(struct filter_data *data)
{
GSList *l;
diff --git a/gobex/gobex-apparam.c b/gobex/gobex-apparam.c
index 6235ff07..7ba8ca6b 100644
--- a/gobex/gobex-apparam.c
+++ b/gobex/gobex-apparam.c
@@ -168,6 +168,13 @@ gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
return count;
}
+#ifdef __TIZEN_PATCH__
+void g_obex_apparam_remove_all(GObexApparam *apparam)
+{
+ g_hash_table_remove_all(apparam->tags);
+}
+#endif
+
GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
const void *value, gsize len)
{
diff --git a/gobex/gobex-apparam.h b/gobex/gobex-apparam.h
index 6c086092..7c55988c 100644
--- a/gobex/gobex-apparam.h
+++ b/gobex/gobex-apparam.h
@@ -30,6 +30,10 @@ typedef struct _GObexApparam GObexApparam;
GObexApparam *g_obex_apparam_decode(const void *data, gsize size);
gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize size);
+#ifdef __TIZEN_PATCH__
+void g_obex_apparam_remove_all(GObexApparam *apparam);
+#endif
+
GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
const void *value, gsize size);
GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
diff --git a/gobex/gobex-transfer.c b/gobex/gobex-transfer.c
index fe535308..a5115bfc 100644
--- a/gobex/gobex-transfer.c
+++ b/gobex/gobex-transfer.c
@@ -425,7 +425,6 @@ guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
transfer->data_consumer = data_func;
-
va_start(args, first_hdr_id);
transfer_put_req_first(transfer, req, first_hdr_id, args);
va_end(args);
diff --git a/lib/bluetooth.c b/lib/bluetooth.c
index 91e714e7..4a569c0f 100644
--- a/lib/bluetooth.c
+++ b/lib/bluetooth.c
@@ -810,7 +810,7 @@ const char *bt_compidtostr(int compid)
case 273:
return "Steelseries ApS";
case 274:
- return "vyzybl Inc.";
+ return "Visybl Inc.";
case 275:
return "Openbrain Technologies, Co., Ltd.";
case 276:
@@ -1082,7 +1082,7 @@ const char *bt_compidtostr(int compid)
case 409:
return "SALTO SYSTEMS S.L.";
case 410:
- return "T-Engine Forum";
+ return "TRON Forum (formerly T-Engine Forum)";
case 411:
return "CUBETECH s.r.o.";
case 412:
@@ -1263,6 +1263,488 @@ const char *bt_compidtostr(int compid)
return "The University of Tokyo";
case 500:
return "UTC Fire and Security";
+ case 501:
+ return "Cool Webthings Limited";
+ case 502:
+ return "DJO Global";
+ case 503:
+ return "Gelliner Limited";
+ case 504:
+ return "Anyka (Guangzhou) Microelectronics Technology Co, LTD";
+ case 505:
+ return "Medtronic, Inc.";
+ case 506:
+ return "Gozio, Inc.";
+ case 507:
+ return "Form Lifting, LLC";
+ case 508:
+ return "Wahoo Fitness, LLC";
+ case 509:
+ return "Kontakt Micro-Location Sp. z o.o.";
+ case 510:
+ return "Radio System Corporation";
+ case 511:
+ return "Freescale Semiconductor, Inc.";
+ case 512:
+ return "Verifone Systems PTe Ltd. Taiwan Branch";
+ case 513:
+ return "AR Timing";
+ case 514:
+ return "Rigado LLC";
+ case 515:
+ return "Kemppi Oy";
+ case 516:
+ return "Tapcentive Inc.";
+ case 517:
+ return "Smartbotics Inc.";
+ case 518:
+ return "Otter Products, LLC";
+ case 519:
+ return "STEMP Inc.";
+ case 520:
+ return "LumiGeek LLC";
+ case 521:
+ return "InvisionHeart Inc.";
+ case 522:
+ return "Macnica Inc.";
+ case 523:
+ return "Jaguar Land Rover Limited";
+ case 524:
+ return "CoroWare Technologies, Inc";
+ case 525:
+ return "Simplo Technology Co., LTD";
+ case 526:
+ return "Omron Healthcare Co., LTD";
+ case 527:
+ return "Comodule GMBH";
+ case 528:
+ return "ikeGPS";
+ case 529:
+ return "Telink Semiconductor Co. Ltd";
+ case 530:
+ return "Interplan Co., Ltd";
+ case 531:
+ return "Wyler AG";
+ case 532:
+ return "IK Multimedia Production srl";
+ case 533:
+ return "Lukoton Experience Oy";
+ case 534:
+ return "MTI Ltd";
+ case 535:
+ return "Tech4home, Lda";
+ case 536:
+ return "Hiotech AB";
+ case 537:
+ return "DOTT Limited";
+ case 538:
+ return "Blue Speck Labs, LLC";
+ case 539:
+ return "Cisco Systems Inc";
+ case 540:
+ return "Mobicomm Inc";
+ case 541:
+ return "Edamic";
+ case 542:
+ return "Goodnet Ltd";
+ case 543:
+ return "Luster Leaf Products Inc";
+ case 544:
+ return "Manus Machina BV";
+ case 545:
+ return "Mobiquity Networks Inc";
+ case 546:
+ return "Praxis Dynamics";
+ case 547:
+ return "Philip Morris Products S.A.";
+ case 548:
+ return "Comarch SA";
+ case 549:
+ return "Nestlé Nespresso S.A.";
+ case 550:
+ return "Merlinia A/S";
+ case 551:
+ return "LifeBEAM Technologies";
+ case 552:
+ return "Twocanoes Labs, LLC";
+ case 553:
+ return "Muoverti Limited";
+ case 554:
+ return "Stamer Musikanlagen GMBH";
+ case 555:
+ return "Tesla Motors";
+ case 556:
+ return "Pharynks Corporation";
+ case 557:
+ return "Lupine";
+ case 558:
+ return "Siemens AG";
+ case 559:
+ return "Huami (Shanghai) Culture Communication CO., LTD";
+ case 560:
+ return "Foster Electric Company, Ltd";
+ case 561:
+ return "ETA SA";
+ case 562:
+ return "x-Senso Solutions Kft";
+ case 563:
+ return "Shenzhen SuLong Communication Ltd";
+ case 564:
+ return "FengFan (BeiJing) Technology Co, Ltd";
+ case 565:
+ return "Qrio Inc";
+ case 566:
+ return "Pitpatpet Ltd";
+ case 567:
+ return "MSHeli s.r.l.";
+ case 568:
+ return "Trakm8 Ltd";
+ case 569:
+ return "JIN CO, Ltd";
+ case 570:
+ return "Alatech Technology";
+ case 571:
+ return "Beijing CarePulse Electronic Technology Co, Ltd";
+ case 572:
+ return "Awarepoint";
+ case 573:
+ return "ViCentra B.V.";
+ case 574:
+ return "Raven Industries";
+ case 575:
+ return "WaveWare Technologies";
+ case 576:
+ return "Argenox Technologies";
+ case 577:
+ return "Bragi GmbH";
+ case 578:
+ return "16Lab Inc";
+ case 579:
+ return "Masimo Corp";
+ case 580:
+ return "Iotera Inc.";
+ case 581:
+ return "Endress+Hauser";
+ case 582:
+ return "ACKme Networks, Inc.";
+ case 583:
+ return "FiftyThree Inc.";
+ case 584:
+ return "Parker Hannifin Corp";
+ case 585:
+ return "Transcranial Ltd";
+ case 586:
+ return "Uwatec AG";
+ case 587:
+ return "Orlan LLC";
+ case 588:
+ return "Blue Clover Devices";
+ case 589:
+ return "M-Way Solutions GmbH";
+ case 590:
+ return "Microtronics Engineering GmbH";
+ case 591:
+ return "Schneider Schreibgeräte GmbH";
+ case 592:
+ return "Sapphire Circuits LLC";
+ case 593:
+ return "Lumo Bodytech Inc.";
+ case 594:
+ return "UKC Technosolution";
+ case 595:
+ return "Xicato Inc.";
+ case 596:
+ return "Playbrush";
+ case 597:
+ return "Dai Nippon Printing Co., Ltd.";
+ case 598:
+ return "G24 Power Limited";
+ case 599:
+ return "AdBabble Local Commerce Inc.";
+ case 600:
+ return "Devialet SA";
+ case 601:
+ return "ALTYOR";
+ case 602:
+ return "University of Applied Sciences Valais/Haute Ecole Valaisanne";
+ case 603:
+ return "Five Interactive, LLC dba Zendo";
+ case 604:
+ return "NetEase (Hangzhou) Network co.Ltd.";
+ case 605:
+ return "Lexmark International Inc.";
+ case 606:
+ return "Fluke Corporation";
+ case 607:
+ return "Yardarm Technologies";
+ case 608:
+ return "SensaRx";
+ case 609:
+ return "SECVRE GmbH";
+ case 610:
+ return "Glacial Ridge Technologies";
+ case 611:
+ return "Identiv, Inc.";
+ case 612:
+ return "DDS, Inc.";
+ case 613:
+ return "SMK Corporation";
+ case 614:
+ return "Schawbel Technologies LLC";
+ case 615:
+ return "XMI Systems SA";
+ case 616:
+ return "Cerevo";
+ case 617:
+ return "Torrox GmbH & Co KG";
+ case 618:
+ return "Gemalto";
+ case 619:
+ return "DEKA Research & Development Corp.";
+ case 620:
+ return "Domster Tadeusz Szydlowski";
+ case 621:
+ return "Technogym SPA";
+ case 622:
+ return "FLEURBAEY BVBA";
+ case 623:
+ return "Aptcode Solutions";
+ case 624:
+ return "LSI ADL Technology";
+ case 625:
+ return "Animas Corp";
+ case 626:
+ return "Alps Electric Co., Ltd.";
+ case 627:
+ return "OCEASOFT";
+ case 628:
+ return "Motsai Research";
+ case 629:
+ return "Geotab";
+ case 630:
+ return "E.G.O. Elektro-Gerätebau GmbH";
+ case 631:
+ return "bewhere inc";
+ case 632:
+ return "Johnson Outdoors Inc";
+ case 633:
+ return "steute Schaltgerate GmbH & Co. KG";
+ case 634:
+ return "Ekomini inc.";
+ case 635:
+ return "DEFA AS";
+ case 636:
+ return "Aseptika Ltd";
+ case 637:
+ return "HUAWEI Technologies Co., Ltd. ( 华为技术有限公司 )";
+ case 638:
+ return "HabitAware, LLC";
+ case 639:
+ return "ruwido austria gmbh";
+ case 640:
+ return "ITEC corporation";
+ case 641:
+ return "StoneL";
+ case 642:
+ return "Sonova AG";
+ case 643:
+ return "Maven Machines, Inc.";
+ case 644:
+ return "Synapse Electronics";
+ case 645:
+ return "Standard Innovation Inc.";
+ case 646:
+ return "RF Code, Inc.";
+ case 647:
+ return "Wally Ventures S.L.";
+ case 648:
+ return "Willowbank Electronics Ltd";
+ case 649:
+ return "SK Telecom";
+ case 650:
+ return "Jetro AS";
+ case 651:
+ return "Code Gears LTD";
+ case 652:
+ return "NANOLINK APS";
+ case 653:
+ return "IF, LLC";
+ case 654:
+ return "RF Digital Corp";
+ case 655:
+ return "Church & Dwight Co., Inc";
+ case 656:
+ return "Multibit Oy";
+ case 657:
+ return "CliniCloud Inc";
+ case 658:
+ return "SwiftSensors";
+ case 659:
+ return "Blue Bite";
+ case 660:
+ return "ELIAS GmbH";
+ case 661:
+ return "Sivantos GmbH";
+ case 662:
+ return "Petzl";
+ case 663:
+ return "storm power ltd";
+ case 664:
+ return "EISST Ltd";
+ case 665:
+ return "Inexess Technology Simma KG";
+ case 666:
+ return "Currant, Inc.";
+ case 667:
+ return "C2 Development, Inc.";
+ case 668:
+ return "Blue Sky Scientific, LLC";
+ case 669:
+ return "ALOTTAZS LABS, LLC";
+ case 670:
+ return "Kupson spol. s r.o.";
+ case 671:
+ return "Areus Engineering GmbH";
+ case 672:
+ return "Impossible Camera GmbH";
+ case 673:
+ return "InventureTrack Systems";
+ case 674:
+ return "LockedUp";
+ case 675:
+ return "Itude";
+ case 676:
+ return "Pacific Lock Company";
+ case 677:
+ return "Tendyron Corporation ( 天地融科技股份有限公司 )";
+ case 678:
+ return "Robert Bosch GmbH";
+ case 679:
+ return "Illuxtron international B.V.";
+ case 680:
+ return "miSport Ltd.";
+ case 681:
+ return "Chargelib";
+ case 682:
+ return "Doppler Lab";
+ case 683:
+ return "BBPOS Limited";
+ case 684:
+ return "RTB Elektronik GmbH & Co. KG";
+ case 685:
+ return "Rx Networks, Inc.";
+ case 686:
+ return "WeatherFlow, Inc.";
+ case 687:
+ return "Technicolor USA Inc.";
+ case 688:
+ return "Bestechnic(Shanghai),Ltd";
+ case 689:
+ return "Raden Inc";
+ case 690:
+ return "JouZen Oy";
+ case 691:
+ return "CLABER S.P.A.";
+ case 692:
+ return "Hyginex, Inc.";
+ case 693:
+ return "HANSHIN ELECTRIC RAILWAY CO.,LTD.";
+ case 694:
+ return "Schneider Electric";
+ case 695:
+ return "Oort Technologies LLC";
+ case 696:
+ return "Chrono Therapeutics";
+ case 697:
+ return "Rinnai Corporation";
+ case 698:
+ return "Swissprime Technologies AG";
+ case 699:
+ return "Koha.,Co.Ltd";
+ case 700:
+ return "Genevac Ltd";
+ case 701:
+ return "Chemtronics";
+ case 702:
+ return "Seguro Technology Sp. z o.o.";
+ case 703:
+ return "Redbird Flight Simulations";
+ case 704:
+ return "Dash Robotics";
+ case 705:
+ return "LINE Corporation";
+ case 706:
+ return "Guillemot Corporation";
+ case 707:
+ return "Techtronic Power Tools Technology Limited";
+ case 708:
+ return "Wilson Sporting Goods";
+ case 709:
+ return "Lenovo (Singapore) Pte Ltd. ( 联想(新加坡) )";
+ case 710:
+ return "Ayatan Sensors";
+ case 711:
+ return "Electronics Tomorrow Limited";
+ case 712:
+ return "VASCO Data Security International, Inc.";
+ case 713:
+ return "PayRange Inc.";
+ case 714:
+ return "ABOV Semiconductor";
+ case 715:
+ return "AINA-Wireless Inc.";
+ case 716:
+ return "Eijkelkamp Soil & Water";
+ case 717:
+ return "BMA ergonomics b.v.";
+ case 718:
+ return "Teva Branded Pharmaceutical Products R&D, Inc.";
+ case 719:
+ return "Anima";
+ case 720:
+ return "3M";
+ case 721:
+ return "Empatica Srl";
+ case 722:
+ return "Afero, Inc.";
+ case 723:
+ return "Powercast Corporation";
+ case 724:
+ return "Secuyou ApS";
+ case 725:
+ return "OMRON Corporation";
+ case 726:
+ return "Send Solutions";
+ case 727:
+ return "NIPPON SYSTEMWARE CO.,LTD.";
+ case 728:
+ return "Neosfar";
+ case 729:
+ return "Fliegl Agrartechnik GmbH";
+ case 730:
+ return "Gilvader";
+ case 731:
+ return "Digi International Inc (R)";
+ case 732:
+ return "DeWalch Technologies, Inc.";
+ case 733:
+ return "Flint Rehabilitation Devices, LLC";
+ case 734:
+ return "Samsung SDS Co., Ltd.";
+ case 735:
+ return "Blur Product Development";
+ case 736:
+ return "University of Michigan";
+ case 737:
+ return "Victron Energy BV";
+ case 738:
+ return "NTT docomo";
+ case 739:
+ return "Carmanah Technologies Corp.";
+ case 740:
+ return "Bytestorm Ltd.";
+ case 741:
+ return "Espressif Incorporated ( 乐鑫信息科技(上海)有限公司 )";
case 65535:
return "internal use";
default:
diff --git a/lib/bluetooth.h b/lib/bluetooth.h
index 852a6b23..3acee0fe 100644
--- a/lib/bluetooth.h
+++ b/lib/bluetooth.h
@@ -119,6 +119,16 @@ struct bt_voice {
#define BT_SNDMTU 12
#define BT_RCVMTU 13
+#ifdef __TIZEN_PATCH__
+#define BT_LE_CONN_PARAM 14
+struct le_conn_param {
+ uint16_t min;
+ uint16_t max;
+ uint16_t latency;
+ uint16_t to_multiplier;
+};
+#endif
+
#define BT_VOICE_TRANSPARENT 0x0003
#define BT_VOICE_CVSD_16BIT 0x0060
diff --git a/lib/bnep.h b/lib/bnep.h
index 0a748361..e7c2c87c 100644
--- a/lib/bnep.h
+++ b/lib/bnep.h
@@ -126,11 +126,9 @@ struct bnep_ext_hdr {
#define BNEPCONNDEL _IOW('B', 201, int)
#define BNEPGETCONNLIST _IOR('B', 210, int)
#define BNEPGETCONNINFO _IOR('B', 211, int)
-#ifdef __TIZEN_PATCH__
#define BNEPGETSUPPFEAT _IOR('B', 212, int)
#define BNEP_SETUP_RESPONSE 0
-#endif
struct bnep_connadd_req {
int sock; /* Connected socket */
diff --git a/lib/hci.c b/lib/hci.c
index c6cc7fc3..70f4cd40 100644
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -592,8 +592,12 @@ static hci_map commands_map[] = {
{ "LE Receiver Test", 228 },
{ "LE Transmitter Test", 229 },
{ "LE Test End", 230 },
+#ifdef __TIZEN_PATCH__
{ "LE Read Maximum Data Length", 231 },
{ "Reserved", 232 },
+#else
+ { "Reserved", 231 },
+#endif
{ NULL }
};
@@ -1085,6 +1089,38 @@ int hci_close_dev(int dd)
/* HCI functions that require open device
* dd - Device descriptor returned by hci_open_dev. */
+#ifdef __TIZEN_PATCH__
+int hci_send_data(int dd, uint16_t handle, uint8_t len, void *data)
+{
+ uint8_t type = HCI_ACLDATA_PKT;
+ hci_acl_hdr ac;
+ struct iovec iv[3];
+ int ivn;
+
+ ac.handle = htobs(handle);
+ ac.dlen= htobs(len);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = 1;
+ iv[1].iov_base = &ac;
+ iv[1].iov_len = HCI_ACL_HDR_SIZE;
+ ivn = 2;
+
+ if (len) {
+ iv[2].iov_base = data;
+ iv[2].iov_len = len;
+ ivn = 3;
+ }
+
+ while (writev(dd, iv, ivn) < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
{
uint8_t type = HCI_COMMAND_PKT;
diff --git a/lib/hci.h b/lib/hci.h
index ae7be46d..edc59c07 100755..100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -2411,6 +2411,7 @@ struct sockaddr_hci {
#define HCI_CHANNEL_USER 1
#define HCI_CHANNEL_MONITOR 2
#define HCI_CHANNEL_CONTROL 3
+#define HCI_CHANNEL_LOGGING 4
struct hci_filter {
uint32_t type_mask;
diff --git a/lib/hci_lib.h b/lib/hci_lib.h
index c766f118..0febe8ea 100644
--- a/lib/hci_lib.h
+++ b/lib/hci_lib.h
@@ -50,6 +50,9 @@ struct hci_version {
int hci_open_dev(int dev_id);
int hci_close_dev(int dd);
+#ifdef __TIZEN_PATCH__
+int hci_send_data(int dd, uint16_t handle, uint8_t len, void *data);
+#endif
int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param);
int hci_send_req(int dd, struct hci_request *req, int timeout);
diff --git a/lib/mgmt.h b/lib/mgmt.h
index 09448f56..d55c8b2a 100755..100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -515,6 +515,21 @@ struct mgmt_rp_remove_advertising {
uint8_t instance;
} __packed;
+#define MGMT_OP_GET_ADV_SIZE_INFO 0x0040
+struct mgmt_cp_get_adv_size_info {
+ uint8_t instance;
+ uint32_t flags;
+} __packed;
+#define MGMT_GET_ADV_SIZE_INFO_SIZE 5
+struct mgmt_rp_get_adv_size_info {
+ uint8_t instance;
+ uint32_t flags;
+ uint8_t max_adv_data_len;
+ uint8_t max_scan_rsp_len;
+} __packed;
+
+#define MGMT_OP_START_LIMITED_DISCOVERY 0x0041
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
uint16_t opcode;
@@ -792,6 +807,8 @@ static const char *mgmt_op[] = {
"Read Advertising Features",
"Add Advertising",
"Remove Advertising",
+ "Get Advertising Size Information", /* 0x0040 */
+ "Start Limited Discovery",
};
static const char *mgmt_ev[] = {
@@ -803,7 +820,7 @@ static const char *mgmt_ev[] = {
"Index Removed",
"New Settings",
"Class of Device Changed",
- "Local Name Changed", /* 0x0008 */
+ "Local Name Changed", /* 0x0008 */
"New Link Key",
"New Long Term Key",
"Device Connected",
@@ -811,7 +828,7 @@ static const char *mgmt_ev[] = {
"Connect Failed",
"PIN Code Request",
"User Confirm Request",
- "User Passkey Request", /* 0x0010 */
+ "User Passkey Request", /* 0x0010 */
"Authentication Failed",
"Device Found",
"Discovering",
@@ -819,7 +836,7 @@ static const char *mgmt_ev[] = {
"Device Unblocked",
"Device Unpaired",
"Passkey Notify",
- "New Identity Resolving Key",
+ "New Identity Resolving Key", /* 0x0018 */
"New Signature Resolving Key",
"Device Added",
"Device Removed",
@@ -827,7 +844,7 @@ static const char *mgmt_ev[] = {
"Unconfigured Index Added",
"Unconfigured Index Removed",
"New Configuration Options",
- "Extended Index Added",
+ "Extended Index Added", /* 0x0020 */
"Extended Index Removed",
"Local Out Of Band Extended Data Updated",
"Advertising Added",
@@ -1211,8 +1228,10 @@ static const char *mgmt_tizen_op[] = {
"LE Set Scan Parameters",
"Set Voice Setting",
"Get Adv Tx Power",
+#ifdef __TIZEN_PATCH__
"Connect BT 6LOWPAN",
"Disconnect BT 6LOWPAN"
+#endif
};
static const char *mgmt_tizen_ev[] = {
@@ -1228,7 +1247,6 @@ static const char *mgmt_tizen_ev[] = {
"LE Connection Update Failed",
"LE Device Found",
"Multi Adv State Change",
- "BT 6LOWPAN state Change"
};
#endif /* End of __TIZEN_PATCH__ */
diff --git a/lib/sdp.c b/lib/sdp.c
index 2107e288..eb408a94 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -932,8 +932,12 @@ int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *buf)
void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)
{
- sdp_data_t *p = sdp_data_get(rec, attr);
+ sdp_data_t *p;
+
+ if (!rec)
+ return;
+ p = sdp_data_get(rec, attr);
if (p) {
rec->attrlist = sdp_list_remove(rec->attrlist, p);
sdp_data_free(p);
@@ -1667,7 +1671,7 @@ void sdp_data_print(sdp_data_t *d)
sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId)
{
- if (rec->attrlist) {
+ if (rec && rec->attrlist) {
sdp_data_t sdpTemplate;
sdp_list_t *p;
@@ -4906,6 +4910,7 @@ int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)
length = 0;
break;
default:
+ sdp_list_free(subseq, free);
goto fail;
}
diff --git a/lib/uuid.c b/lib/uuid.c
index 4f34b17f..20b67d03 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -138,46 +138,35 @@ int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
*/
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
{
- if (!uuid) {
+ bt_uuid_t tmp;
+ unsigned int data0;
+ unsigned short data1;
+ unsigned short data2;
+ unsigned short data3;
+ unsigned int data4;
+ unsigned short data5;
+ const uint8_t *data;
+
+ if (!uuid || uuid->type == BT_UUID_UNSPEC) {
snprintf(str, n, "NULL");
return -EINVAL;
}
- switch (uuid->type) {
- case BT_UUID16:
- snprintf(str, n, "%.4x", uuid->value.u16);
- break;
- case BT_UUID32:
- snprintf(str, n, "%.8x", uuid->value.u32);
- break;
- case BT_UUID128: {
- unsigned int data0;
- unsigned short data1;
- unsigned short data2;
- unsigned short data3;
- unsigned int data4;
- unsigned short data5;
-
- const uint8_t *data = (uint8_t *) &uuid->value.u128;
-
- memcpy(&data0, &data[0], 4);
- memcpy(&data1, &data[4], 2);
- memcpy(&data2, &data[6], 2);
- memcpy(&data3, &data[8], 2);
- memcpy(&data4, &data[10], 4);
- memcpy(&data5, &data[14], 2);
-
- snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+ /* Convert to 128 Bit format */
+ bt_uuid_to_uuid128(uuid, &tmp);
+ data = (uint8_t *) &tmp.value.u128;
+
+ memcpy(&data0, &data[0], 4);
+ memcpy(&data1, &data[4], 2);
+ memcpy(&data2, &data[6], 2);
+ memcpy(&data3, &data[8], 2);
+ memcpy(&data4, &data[10], 4);
+ memcpy(&data5, &data[14], 2);
+
+ snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
ntohl(data0), ntohs(data1),
ntohs(data2), ntohs(data3),
ntohl(data4), ntohs(data5));
- }
- break;
- case BT_UUID_UNSPEC:
- default:
- snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type);
- return -EINVAL; /* Enum type of UUID not set */
- }
return 0;
}
@@ -289,7 +278,12 @@ int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
int bt_uuid_strcmp(const void *a, const void *b)
{
- return strcasecmp(a, b);
+ bt_uuid_t u1, u2;
+
+ bt_string_to_uuid(&u1, a);
+ bt_string_to_uuid(&u2, b);
+
+ return bt_uuid_cmp(&u1, &u2);
}
int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
@@ -301,7 +295,8 @@ int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
bt_put_le16(src->value.u16, dst);
return 0;
case BT_UUID32:
- bt_uuid_to_uuid128(src, &uuid);
+ bt_uuid32_to_uuid128(src, &uuid);
+ src = &uuid;
/* Fallthrough */
case BT_UUID128:
/* Convert from 128-bit BE to LE */
diff --git a/lib/uuid.h b/lib/uuid.h
index 98e96276..542ef606 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -109,6 +109,12 @@ extern "C" {
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
+#ifdef __TIZEN_PATCH__
+/* Samsung Accessary Protocol UUIDs */
+#define WEARABLE_OLD_SAP_UUID "a49eb41e-cb06-495c-9f4f-aa80a90cdf4a"
+#define WEARABLE_NEW_SAP_UUID "a49eb41e-cb06-495c-9f4f-bb80a90cdf00"
+#endif
+
/* GATT UUIDs section */
#define GATT_PRIM_SVC_UUID 0x2800
#define GATT_SND_SVC_UUID 0x2801
diff --git a/monitor/a2dp.c b/monitor/a2dp.c
new file mode 100644
index 00000000..94f9758a
--- /dev/null
+++ b/monitor/a2dp.c
@@ -0,0 +1,638 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "a2dp.h"
+
+#define BASE_INDENT 4
+
+/* Codec Types */
+#define A2DP_CODEC_SBC 0x00
+#define A2DP_CODEC_MPEG12 0x01
+#define A2DP_CODEC_MPEG24 0x02
+#define A2DP_CODEC_ATRAC 0x04
+#define A2DP_CODEC_VENDOR 0xff
+
+/* Vendor Specific A2DP Codecs */
+#define APTX_VENDOR_ID 0x0000004f
+#define APTX_CODEC_ID 0x0001
+#define LDAC_VENDOR_ID 0x0000012d
+#define LDAC_CODEC_ID 0x00aa
+
+struct bit_desc {
+ uint8_t bit_num;
+ const char *str;
+};
+
+static const struct bit_desc sbc_frequency_table[] = {
+ { 7, "16000" },
+ { 6, "32000" },
+ { 5, "44100" },
+ { 4, "48000" },
+ { }
+};
+
+static const struct bit_desc sbc_channel_mode_table[] = {
+ { 3, "Mono" },
+ { 2, "Dual Channel" },
+ { 1, "Stereo" },
+ { 0, "Joint Stereo" },
+ { }
+};
+
+static const struct bit_desc sbc_blocklen_table[] = {
+ { 7, "4" },
+ { 6, "8" },
+ { 5, "12" },
+ { 4, "16" },
+ { }
+};
+
+static const struct bit_desc sbc_subbands_table[] = {
+ { 3, "4" },
+ { 2, "8" },
+ { }
+};
+
+static const struct bit_desc sbc_allocation_table[] = {
+ { 1, "SNR" },
+ { 0, "Loudness" },
+ { }
+};
+
+static const struct bit_desc mpeg12_layer_table[] = {
+ { 7, "Layer I (mp1)" },
+ { 6, "Layer II (mp2)" },
+ { 5, "Layer III (mp3)" },
+ { }
+};
+
+static const struct bit_desc mpeg12_channel_mode_table[] = {
+ { 3, "Mono" },
+ { 2, "Dual Channel" },
+ { 1, "Stereo" },
+ { 0, "Joint Stereo" },
+ { }
+};
+
+static const struct bit_desc mpeg12_frequency_table[] = {
+ { 5, "16000" },
+ { 4, "22050" },
+ { 3, "24000" },
+ { 2, "32000" },
+ { 1, "44100" },
+ { 0, "48000" },
+ { }
+};
+
+static const struct bit_desc mpeg12_bitrate_table[] = {
+ { 14, "1110" },
+ { 13, "1101" },
+ { 12, "1100" },
+ { 11, "1011" },
+ { 10, "1010" },
+ { 9, "1001" },
+ { 8, "1000" },
+ { 7, "0111" },
+ { 6, "0110" },
+ { 5, "0101" },
+ { 4, "0100" },
+ { 3, "0011" },
+ { 2, "0010" },
+ { 1, "0001" },
+ { 0, "0000" },
+ { }
+};
+
+static const struct bit_desc aac_object_type_table[] = {
+ { 7, "MPEG-2 AAC LC" },
+ { 6, "MPEG-4 AAC LC" },
+ { 5, "MPEG-4 AAC LTP" },
+ { 4, "MPEG-4 AAC scalable" },
+ { 3, "RFA (b3)" },
+ { 2, "RFA (b2)" },
+ { 1, "RFA (b1)" },
+ { 0, "RFA (b0)" },
+ { }
+};
+
+static const struct bit_desc aac_frequency_table[] = {
+ { 15, "8000" },
+ { 14, "11025" },
+ { 13, "12000" },
+ { 12, "16000" },
+ { 11, "22050" },
+ { 10, "24000" },
+ { 9, "32000" },
+ { 8, "44100" },
+ { 7, "48000" },
+ { 6, "64000" },
+ { 5, "88200" },
+ { 4, "96000" },
+ { }
+};
+
+static const struct bit_desc aac_channels_table[] = {
+ { 3, "1" },
+ { 2, "2" },
+ { }
+};
+
+static const struct bit_desc aptx_frequency_table[] = {
+ { 7, "16000" },
+ { 6, "32000" },
+ { 5, "44100" },
+ { 4, "48000" },
+ { }
+};
+
+static const struct bit_desc aptx_channel_mode_table[] = {
+ { 0, "Mono" },
+ { 1, "Stereo" },
+ { }
+};
+
+static void print_value_bits(uint8_t indent, uint32_t value,
+ const struct bit_desc *table)
+{
+ int i;
+
+ for (i = 0; table[i].str; i++) {
+ if (value & (1 << table[i].bit_num))
+ print_field("%*c%s", indent + 2, ' ', table[i].str);
+ }
+}
+
+static const char *find_value_bit(uint32_t value,
+ const struct bit_desc *table)
+{
+ int i;
+
+ for (i = 0; table[i].str; i++) {
+ if (value & (1 << table[i].bit_num))
+ return table[i].str;
+ }
+
+ return "Unknown";
+}
+
+static const char *vndcodec2str(uint32_t vendor_id, uint16_t codec_id)
+{
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ return "aptX";
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ return "LDAC";
+
+ return "Unknown";
+}
+
+static bool codec_sbc_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', cap & 0xf0);
+ print_value_bits(BASE_INDENT, cap & 0xf0, sbc_frequency_table);
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', cap & 0x0f);
+ print_value_bits(BASE_INDENT, cap & 0x0f, sbc_channel_mode_table);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cBlock Length: 0x%02x", BASE_INDENT, ' ', cap & 0xf0);
+ print_value_bits(BASE_INDENT, cap & 0xf0, sbc_blocklen_table);
+
+ print_field("%*cSubbands: 0x%02x", BASE_INDENT, ' ', cap & 0x0c);
+ print_value_bits(BASE_INDENT, cap & 0x0c, sbc_subbands_table);
+
+ print_field("%*cAllocation Method: 0x%02x", BASE_INDENT, ' ',
+ cap & 0x03);
+ print_value_bits(BASE_INDENT, cap & 0x03, sbc_allocation_table);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMinimum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMaximum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ return true;
+}
+
+static bool codec_sbc_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0xf0, sbc_frequency_table),
+ cap & 0xf0);
+
+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0x0f, sbc_channel_mode_table),
+ cap & 0x0f);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cBlock Length: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0xf0, sbc_blocklen_table),
+ cap & 0xf0);
+
+ print_field("%*cSubbands: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0x0c, sbc_subbands_table),
+ cap & 0x0c);
+
+ print_field("%*cAllocation Method: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0x03, sbc_allocation_table),
+ cap & 0x03);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMinimum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMaximum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ return true;
+}
+
+static bool codec_mpeg12_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t layer;
+ uint8_t chan;
+ uint8_t freq;
+ uint16_t bitrate;
+ bool crc, mpf, vbr;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ layer = (cap >> 8) & 0xe0;
+ crc = cap & 0x1000;
+ chan = (cap >> 8) & 0x0f;
+ mpf = cap & 0x0040;
+ freq = cap & 0x003f;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ vbr = cap & 0x8000;
+ bitrate = cap & 0x7fff;
+
+ print_field("%*cLayer: 0x%02x", BASE_INDENT, ' ', layer);
+ print_value_bits(BASE_INDENT, layer, mpeg12_layer_table);
+
+ print_field("%*cCRC: %s", BASE_INDENT, ' ', crc ? "Yes" : "No");
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', chan);
+ print_value_bits(BASE_INDENT, chan, mpeg12_channel_mode_table);
+
+ print_field("%*cMedia Payload Format: %s", BASE_INDENT, ' ',
+ mpf ? "RFC-2250 RFC-3119" : "RFC-2250");
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+ print_value_bits(BASE_INDENT, freq, mpeg12_frequency_table);
+
+ if (!vbr) {
+ print_field("%*cBitrate Index: 0x%04x", BASE_INDENT, ' ',
+ bitrate);
+ print_value_bits(BASE_INDENT, freq, mpeg12_bitrate_table);
+ }
+
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
+static bool codec_mpeg12_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t layer;
+ uint8_t chan;
+ uint8_t freq;
+ uint16_t bitrate;
+ bool crc, mpf, vbr;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ layer = (cap >> 8) & 0xe0;
+ crc = cap & 0x1000;
+ chan = (cap >> 8) & 0x0f;
+ mpf = cap & 0x0040;
+ freq = cap & 0x003f;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ vbr = cap & 0x8000;
+ bitrate = cap & 0x7fff;
+
+ print_field("%*cLayer: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(layer, mpeg12_layer_table),
+ layer);
+
+ print_field("%*cCRC: %s", BASE_INDENT, ' ', crc ? "Yes" : "No");
+
+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(chan, mpeg12_channel_mode_table),
+ chan);
+
+ print_field("%*cMedia Payload Format: %s", BASE_INDENT, ' ',
+ mpf ? "RFC-2250 RFC-3119" : "RFC-2250");
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(freq, mpeg12_frequency_table),
+ freq);
+
+ if (!vbr)
+ print_field("%*cBitrate Index: %s (0x%04x)", BASE_INDENT, ' ',
+ find_value_bit(freq, mpeg12_bitrate_table),
+ bitrate);
+
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
+static bool codec_aac_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t type;
+ uint16_t freq;
+ uint8_t chan;
+ uint32_t bitrate;
+ bool vbr;
+
+ if (losc != 6)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ type = cap >> 8;
+ freq = cap << 8;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ freq |= (cap >> 8) & 0xf0;
+ chan = (cap >> 8) & 0x0c;
+ bitrate = (cap << 16) & 0x7f0000;
+ vbr = cap & 0x0080;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ bitrate |= cap;
+
+ print_field("%*cObject Type: 0x%02x", BASE_INDENT, ' ', type);
+ print_value_bits(BASE_INDENT, type, aac_object_type_table);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+ print_value_bits(BASE_INDENT, freq, aac_frequency_table);
+
+ print_field("%*cChannels: 0x%02x", BASE_INDENT, ' ', chan);
+ print_value_bits(BASE_INDENT, chan, aac_channels_table);
+
+ print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
+static bool codec_aac_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t type;
+ uint16_t freq;
+ uint8_t chan;
+ uint32_t bitrate;
+ bool vbr;
+
+ if (losc != 6)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ type = cap >> 8;
+ freq = cap << 8;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ freq |= (cap >> 8) & 0xf0;
+ chan = (cap >> 8) & 0x0c;
+ bitrate = (cap << 16) & 0x7f0000;
+ vbr = cap & 0x0080;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ bitrate |= cap;
+
+ print_field("%*cObject Type: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(type, aac_object_type_table), type);
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(freq, aac_frequency_table), freq);
+
+ print_field("%*cChannels: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(chan, aac_channels_table), chan);
+
+ print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
+static bool codec_vendor_aptx_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 1)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT + 2, ' ', cap & 0xf0);
+ print_value_bits(BASE_INDENT + 2, cap & 0xf0, aptx_frequency_table);
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ',
+ cap & 0x0f);
+ print_value_bits(BASE_INDENT + 2, cap & 0x0f, aptx_channel_mode_table);
+
+ return true;
+}
+
+static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+
+ if (losc != 2)
+ return false;
+
+ l2cap_frame_get_le16(frame, &cap);
+
+ print_field("%*cUnknown: 0x%04x", BASE_INDENT + 2, ' ', cap);
+
+ return true;
+}
+
+static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint32_t vendor_id = 0;
+ uint16_t codec_id = 0;
+
+ if (losc < 6)
+ return false;
+
+ l2cap_frame_get_le32(frame, &vendor_id);
+ l2cap_frame_get_le16(frame, &codec_id);
+
+ losc -= 6;
+
+ print_field("%*cVendor ID: %s (0x%08x)", BASE_INDENT, ' ',
+ bt_compidtostr(vendor_id), vendor_id);
+
+ print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT,
+ ' ', vndcodec2str(vendor_id, codec_id), codec_id);
+
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ return codec_vendor_aptx_cap(losc, frame);
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ return codec_vendor_ldac(losc, frame);
+
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
+static bool codec_vendor_aptx_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 1)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT + 2, ' ',
+ find_value_bit(cap & 0xf0, aptx_frequency_table),
+ cap & 0xf0);
+
+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT + 2, ' ',
+ find_value_bit(cap & 0x0f, aptx_channel_mode_table),
+ cap & 0x0f);
+
+ return true;
+}
+
+static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint32_t vendor_id = 0;
+ uint16_t codec_id = 0;
+
+ if (losc < 6)
+ return false;
+
+ l2cap_frame_get_le32(frame, &vendor_id);
+ l2cap_frame_get_le16(frame, &codec_id);
+
+ losc -= 6;
+
+ print_field("%*cVendor ID: %s (0x%08x)", BASE_INDENT, ' ',
+ bt_compidtostr(vendor_id), vendor_id);
+
+ print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT,
+ ' ', vndcodec2str(vendor_id, codec_id), codec_id);
+
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ return codec_vendor_aptx_cfg(losc, frame);
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ return codec_vendor_ldac(losc, frame);
+
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
+bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+ switch (codec) {
+ case A2DP_CODEC_SBC:
+ return codec_sbc_cap(losc, frame);
+ case A2DP_CODEC_MPEG12:
+ return codec_mpeg12_cap(losc, frame);
+ case A2DP_CODEC_MPEG24:
+ return codec_aac_cap(losc, frame);
+ case A2DP_CODEC_VENDOR:
+ return codec_vendor_cap(losc, frame);
+ default:
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ return true;
+ }
+}
+
+bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+ switch (codec) {
+ case A2DP_CODEC_SBC:
+ return codec_sbc_cfg(losc, frame);
+ case A2DP_CODEC_MPEG12:
+ return codec_mpeg12_cfg(losc, frame);
+ case A2DP_CODEC_MPEG24:
+ return codec_aac_cfg(losc, frame);
+ case A2DP_CODEC_VENDOR:
+ return codec_vendor_cfg(losc, frame);
+ default:
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ return true;
+ }
+}
diff --git a/monitor/a2dp.h b/monitor/a2dp.h
new file mode 100644
index 00000000..72a8f1f4
--- /dev/null
+++ b/monitor/a2dp.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
+
+bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
diff --git a/monitor/analyze.c b/monitor/analyze.c
index eea3c9ee..0f2d19a7 100644
--- a/monitor/analyze.c
+++ b/monitor/analyze.c
@@ -255,18 +255,18 @@ void analyze_trace(const char *path)
{
struct btsnoop *btsnoop_file;
unsigned long num_packets = 0;
- uint32_t type;
+ uint32_t format;
btsnoop_file = btsnoop_open(path, BTSNOOP_FLAG_PKLG_SUPPORT);
if (!btsnoop_file)
return;
- type = btsnoop_get_type(btsnoop_file);
+ format = btsnoop_get_format(btsnoop_file);
- switch (type) {
- case BTSNOOP_TYPE_HCI:
- case BTSNOOP_TYPE_UART:
- case BTSNOOP_TYPE_MONITOR:
+ switch (format) {
+ case BTSNOOP_FORMAT_HCI:
+ case BTSNOOP_FORMAT_UART:
+ case BTSNOOP_FORMAT_MONITOR:
break;
default:
fprintf(stderr, "Unsupported packet format\n");
@@ -309,6 +309,9 @@ void analyze_trace(const char *path)
case BTSNOOP_OPCODE_SCO_RX_PKT:
sco_pkt(&tv, index, buf, pktlen);
break;
+ case BTSNOOP_OPCODE_OPEN_INDEX:
+ case BTSNOOP_OPCODE_CLOSE_INDEX:
+ break;
default:
fprintf(stderr, "Wrong opcode %u\n", opcode);
goto done;
diff --git a/monitor/avctp.c b/monitor/avctp.c
index c599aa46..a024a0fc 100644
--- a/monitor/avctp.c
+++ b/monitor/avctp.c
@@ -64,7 +64,7 @@
#define AVC_SUBUNIT_PRINTER 0x02
#define AVC_SUBUNIT_DISC 0x03
#define AVC_SUBUNIT_TAPE 0x04
-#define AVC_SUBUNIT_TURNER 0x05
+#define AVC_SUBUNIT_TUNER 0x05
#define AVC_SUBUNIT_CA 0x06
#define AVC_SUBUNIT_CAMERA 0x07
#define AVC_SUBUNIT_PANEL 0x09
@@ -141,6 +141,7 @@
#define AVRCP_CHANGE_PATH 0x72
#define AVRCP_GET_ITEM_ATTRIBUTES 0x73
#define AVRCP_PLAY_ITEM 0x74
+#define AVRCP_GET_TOTAL_NUMBER_OF_ITEMS 0x75
#define AVRCP_SEARCH 0x80
#define AVRCP_ADD_TO_NOW_PLAYING 0x90
#define AVRCP_GENERAL_REJECT 0xA0
@@ -182,6 +183,11 @@
#define AVRCP_MEDIA_SEARCH 0x02
#define AVRCP_MEDIA_NOW_PLAYING 0x03
+/* Media Item Type */
+#define AVRCP_MEDIA_PLAYER_ITEM_TYPE 0x01
+#define AVRCP_FOLDER_ITEM_TYPE 0x02
+#define AVRCP_MEDIA_ELEMENT_ITEM_TYPE 0x03
+
/* operands in passthrough commands */
#define AVC_PANEL_VOLUME_UP 0x41
#define AVC_PANEL_VOLUME_DOWN 0x42
@@ -253,8 +259,8 @@ static const char *subunit2str(uint8_t subunit)
return "Disc";
case AVC_SUBUNIT_TAPE:
return "Tape";
- case AVC_SUBUNIT_TURNER:
- return "Turner";
+ case AVC_SUBUNIT_TUNER:
+ return "Tuner";
case AVC_SUBUNIT_CA:
return "CA";
case AVC_SUBUNIT_CAMERA:
@@ -262,7 +268,7 @@ static const char *subunit2str(uint8_t subunit)
case AVC_SUBUNIT_PANEL:
return "Panel";
case AVC_SUBUNIT_BULLETIN_BOARD:
- return "Bulleting Board";
+ return "Bulletin Board";
case AVC_SUBUNIT_CAMERA_STORAGE:
return "Camera Storage";
case AVC_SUBUNIT_VENDOR_UNIQUE:
@@ -362,7 +368,7 @@ static const char *error2str(uint8_t status)
case AVRCP_STATUS_INVALID_SCOPE:
return "Invalid Scope";
case AVRCP_STATUS_OUT_OF_BOUNDS:
- return "Range Out of Bonds";
+ return "Range Out of Bounds";
case AVRCP_STATUS_MEDIA_IN_USE:
return "Media in Use";
case AVRCP_STATUS_IS_DIRECTORY:
@@ -370,7 +376,7 @@ static const char *error2str(uint8_t status)
case AVRCP_STATUS_NOW_PLAYING_LIST_FULL:
return "Now Playing List Full";
case AVRCP_STATUS_SEARCH_NOT_SUPPORTED:
- return "Seach Not Supported";
+ return "Search Not Supported";
case AVRCP_STATUS_SEARCH_IN_PROGRESS:
return "Search in Progress";
case AVRCP_STATUS_INVALID_PLAYER_ID:
@@ -435,6 +441,8 @@ static const char *pdu2str(uint8_t pduid)
return "GetItemAttributes";
case AVRCP_PLAY_ITEM:
return "PlayItem";
+ case AVRCP_GET_TOTAL_NUMBER_OF_ITEMS:
+ return "GetTotalNumOfItems";
case AVRCP_SEARCH:
return "Search";
case AVRCP_ADD_TO_NOW_PLAYING:
@@ -512,9 +520,9 @@ static const char *value2str(uint8_t attr, uint8_t value)
case 0x01:
return "OFF";
case 0x02:
- return "All Track Suffle";
+ return "All Track Shuffle";
case 0x03:
- return "Group Suffle";
+ return "Group Shuffle";
default:
return "Reserved";
}
@@ -677,6 +685,106 @@ static char *op2str(uint8_t op)
}
}
+static const char *type2str(uint8_t type)
+{
+ switch (type) {
+ case AVRCP_MEDIA_PLAYER_ITEM_TYPE:
+ return "Media Player";
+ case AVRCP_FOLDER_ITEM_TYPE:
+ return "Folder";
+ case AVRCP_MEDIA_ELEMENT_ITEM_TYPE:
+ return "Media Element";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *playertype2str(uint8_t type)
+{
+ switch (type & 0x0F) {
+ case 0x01:
+ return "Audio";
+ case 0x02:
+ return "Video";
+ case 0x03:
+ return "Audio, Video";
+ case 0x04:
+ return "Audio Broadcasting";
+ case 0x05:
+ return "Audio, Audio Broadcasting";
+ case 0x06:
+ return "Video, Audio Broadcasting";
+ case 0x07:
+ return "Audio, Video, Audio Broadcasting";
+ case 0x08:
+ return "Video Broadcasting";
+ case 0x09:
+ return "Audio, Video Broadcasting";
+ case 0x0A:
+ return "Video, Video Broadcasting";
+ case 0x0B:
+ return "Audio, Video, Video Broadcasting";
+ case 0x0C:
+ return "Audio Broadcasting, Video Broadcasting";
+ case 0x0D:
+ return "Audio, Audio Broadcasting, Video Broadcasting";
+ case 0x0E:
+ return "Video, Audio Broadcasting, Video Broadcasting";
+ case 0x0F:
+ return "Audio, Video, Audio Broadcasting, Video Broadcasting";
+ }
+
+ return "None";
+}
+
+static const char *playersubtype2str(uint32_t subtype)
+{
+ switch (subtype & 0x03) {
+ case 0x01:
+ return "Audio Book";
+ case 0x02:
+ return "Podcast";
+ case 0x03:
+ return "Audio Book, Podcast";
+ }
+
+ return "None";
+}
+
+static const char *foldertype2str(uint8_t type)
+{
+ switch (type) {
+ case 0x00:
+ return "Mixed";
+ case 0x01:
+ return "Titles";
+ case 0x02:
+ return "Albums";
+ case 0x03:
+ return "Artists";
+ case 0x04:
+ return "Genres";
+ case 0x05:
+ return "Playlists";
+ case 0x06:
+ return "Years";
+ }
+
+ return "Reserved";
+}
+
+static const char *elementtype2str(uint8_t type)
+{
+ switch (type) {
+ case 0x00:
+ return "Audio";
+ case 0x01:
+ return "Video";
+ }
+
+ return "Reserved";
+}
+
static bool avrcp_passthrough_packet(struct avctp_frame *avctp_frame,
uint8_t indent)
{
@@ -1096,10 +1204,10 @@ static bool avrcp_get_element_attributes(struct avctp_frame *avctp_frame,
for (; num > 0; num--) {
uint32_t attr;
- if (!l2cap_frame_get_be32(frame, &attr))
+ if (!l2cap_frame_get_le32(frame, &attr))
return false;
- print_field("%*cAttribute: 0x%08x (%s)", (indent - 8),
+ print_field("%*cAttributeID: 0x%08x (%s)", (indent - 8),
' ', attr, mediattr2str(attr));
}
@@ -1317,7 +1425,7 @@ response:
printf("(UNPLUGGED)\n");
break;
default:
- printf("(UNKOWN)\n");
+ printf("(UNKNOWN)\n");
break;
}
break;
@@ -1637,6 +1745,639 @@ static bool avrcp_control_packet(struct avctp_frame *avctp_frame)
}
}
+static const char *dir2str(uint8_t dir)
+{
+ switch (dir) {
+ case 0x00:
+ return "Folder Up";
+ case 0x01:
+ return "Folder Down";
+ }
+
+ return "Reserved";
+}
+
+static bool avrcp_change_path(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint64_t uid;
+ uint32_t items;
+ uint16_t uidcounter;
+ uint8_t dir, status, indent = 2;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ if (frame->size < 11) {
+ print_field("%*cPDU Malformed", indent, ' ');
+ packet_hexdump(frame->data, frame->size);
+ return false;
+ }
+
+ if (!l2cap_frame_get_be16(frame, &uidcounter))
+ return false;
+
+ print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ',
+ uidcounter, uidcounter);
+
+ if (!l2cap_frame_get_u8(frame, &dir))
+ return false;
+
+ print_field("%*cDirection: 0x%02x (%s)", indent, ' ',
+ dir, dir2str(dir));
+
+ if (!l2cap_frame_get_be64(frame, &uid))
+ return false;
+
+ print_field("%*cFolderUID: 0x%16" PRIx64 " (%" PRIu64 ")", indent, ' ',
+ uid, uid);
+
+ return true;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ',
+ status, error2str(status));
+
+ if (frame->size == 1)
+ return false;
+
+ if (!l2cap_frame_get_be32(frame, &items))
+ return false;
+
+ print_field("%*cNumber of Items: 0x%04x (%u)", indent, ' ',
+ items, items);
+
+ return true;
+}
+
+
+static struct {
+ const char *str;
+ bool reserved;
+} features_table[] = {
+ /* Ignore passthrough bits */
+ [58] = { "Advanced Control Player" },
+ [59] = { "Browsing" },
+ [60] = { "Searching" },
+ [61] = { "AddToNowPlaying" },
+ [62] = { "Unique UIDs" },
+ [63] = { "OnlyBrowsableWhenAddressed" },
+ [64] = { "OnlySearchableWhenAddressed" },
+ [65] = { "NowPlaying" },
+ [66] = { "UIDPersistency" },
+ /* 67-127 reserved */
+ [67 ... 127] = { .reserved = true },
+};
+
+static void print_features(uint8_t features[16], uint8_t indent)
+{
+ int i;
+
+ for (i = 0; i < 127; i++) {
+ if (!(features[i / 8] & (1 << (i % 8))))
+ continue;
+
+ if (features_table[i].reserved) {
+ print_text(COLOR_WHITE_BG, "Unknown bit %u", i);
+ continue;
+ }
+
+ if (!features_table[i].str)
+ continue;
+
+ print_field("%*c%s", indent, ' ', features_table[i].str);
+ }
+}
+
+static bool avrcp_media_player_item(struct avctp_frame *avctp_frame,
+ uint8_t indent)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint16_t id, charset, namelen;
+ uint8_t type, status, i;
+ uint32_t subtype;
+ uint8_t features[16];
+
+ if (!l2cap_frame_get_be16(frame, &id))
+ return false;
+
+ print_field("%*cPlayerID: 0x%04x (%u)", indent, ' ', id, id);
+
+ if (!l2cap_frame_get_u8(frame, &type))
+ return false;
+
+ print_field("%*cPlayerType: 0x%04x (%s)", indent, ' ',
+ type, playertype2str(type));
+
+ if (!l2cap_frame_get_be32(frame, &subtype))
+ return false;
+
+ print_field("%*cPlayerSubType: 0x%08x (%s)", indent, ' ',
+ subtype, playersubtype2str(subtype));
+
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cPlayStatus: 0x%02x (%s)", indent, ' ',
+ status, playstatus2str(status));
+
+ printf("%*cFeatures: 0x", indent+8, ' ');
+
+ for (i = 0; i < 16; i++) {
+ if (!l2cap_frame_get_u8(frame, &features[i]))
+ return false;
+
+ printf("%02x", features[i]);
+ }
+
+ printf("\n");
+
+ print_features(features, indent + 2);
+
+ if (!l2cap_frame_get_be16(frame, &charset))
+ return false;
+
+ print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ',
+ charset, charset2str(charset));
+
+ if (!l2cap_frame_get_be16(frame, &namelen))
+ return false;
+
+ print_field("%*cNameLength: 0x%04x (%u)", indent, ' ',
+ namelen, namelen);
+
+ printf("%*cName: ", indent+8, ' ');
+ for (; namelen > 0; namelen--) {
+ uint8_t c;
+
+ if (!l2cap_frame_get_u8(frame, &c))
+ return false;
+ printf("%1c", isprint(c) ? c : '.');
+ }
+ printf("\n");
+
+ return true;
+}
+
+static bool avrcp_folder_item(struct avctp_frame *avctp_frame,
+ uint8_t indent)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint8_t type, playable;
+ uint16_t charset, namelen;
+ uint64_t uid;
+
+ if (frame->size < 14) {
+ printf("PDU Malformed\n");
+ return false;
+ }
+
+ if (!l2cap_frame_get_be64(frame, &uid))
+ return false;
+
+ print_field("%*cFolderUID: 0x%16" PRIx64 " (%" PRIu64 ")", indent, ' ',
+ uid, uid);
+
+ if (!l2cap_frame_get_u8(frame, &type))
+ return false;
+
+ print_field("%*cFolderType: 0x%02x (%s)", indent, ' ',
+ type, foldertype2str(type));
+
+ if (!l2cap_frame_get_u8(frame, &playable))
+ return false;
+
+ print_field("%*cIsPlayable: 0x%02x (%s)", indent, ' ', playable,
+ playable & 0x01 ? "True" : "False");
+
+ if (!l2cap_frame_get_be16(frame, &charset))
+ return false;
+
+ print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ',
+ charset, charset2str(charset));
+
+ if (!l2cap_frame_get_be16(frame, &namelen))
+ return false;
+
+ print_field("%*cNameLength: 0x%04x (%u)", indent, ' ',
+ namelen, namelen);
+
+ print_field("%*cName: ", indent, ' ');
+ for (; namelen > 0; namelen--) {
+ uint8_t c;
+ if (!l2cap_frame_get_u8(frame, &c))
+ return false;
+
+ printf("%1c", isprint(c) ? c : '.');
+ }
+
+ return true;
+}
+
+static bool avrcp_attribute_entry_list(struct avctp_frame *avctp_frame,
+ uint8_t indent, uint8_t count)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+
+ for (; count > 0; count--) {
+ uint32_t attr;
+ uint16_t charset;
+ uint8_t len;
+
+ if (!l2cap_frame_get_be32(frame, &attr))
+ return false;
+
+ print_field("%*cAttributeID: 0x%08x (%s)", indent, ' ',
+ attr, mediattr2str(attr));
+
+ if (!l2cap_frame_get_be16(frame, &charset))
+ return false;
+
+ print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ',
+ charset, charset2str(charset));
+
+ if (!l2cap_frame_get_u8(frame, &len))
+ return false;
+
+ print_field("%*cAttributeLength: 0x%02x (%u)", indent, ' ',
+ len, len);
+
+ print_field("%*cAttributeValue: ", indent, ' ');
+ for (; len > 0; len--) {
+ uint8_t c;
+
+ if (!l2cap_frame_get_u8(frame, &c))
+ return false;
+
+ printf("%1c", isprint(c) ? c : '.');
+ }
+ }
+
+ return true;
+}
+
+static bool avrcp_media_element_item(struct avctp_frame *avctp_frame,
+ uint8_t indent)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint64_t uid;
+ uint16_t charset, namelen;
+ uint8_t type, count;
+
+ if (!l2cap_frame_get_be64(frame, &uid))
+ return false;
+
+ print_field("%*cElementUID: 0x%16" PRIx64 " (%" PRIu64 ")",
+ indent, ' ', uid, uid);
+
+ if (!l2cap_frame_get_u8(frame, &type))
+ return false;
+
+ print_field("%*cElementType: 0x%02x (%s)", indent, ' ',
+ type, elementtype2str(type));
+
+ if (!l2cap_frame_get_be16(frame, &charset))
+ return false;
+
+ print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ',
+ charset, charset2str(charset));
+
+ if (!l2cap_frame_get_be16(frame, &namelen))
+ return false;
+
+ print_field("%*cNameLength: 0x%04x (%u)", indent, ' ',
+ namelen, namelen);
+
+ print_field("%*cName: ", indent, ' ');
+ for (; namelen > 0; namelen--) {
+ uint8_t c;
+ if (!l2cap_frame_get_u8(frame, &c))
+ return false;
+
+ printf("%1c", isprint(c) ? c : '.');
+ }
+
+ if (!l2cap_frame_get_u8(frame, &count))
+ return false;
+
+ print_field("%*cAttributeCount: 0x%02x (%u)", indent, ' ',
+ count, count);
+
+ if (!avrcp_attribute_entry_list(avctp_frame, indent, count))
+ return false;
+
+ return true;
+}
+
+static bool avrcp_general_reject(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint8_t status, indent = 2;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ print_field("%*cPDU Malformed", indent, ' ');
+ packet_hexdump(frame->data, frame->size);
+
+ return true;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ',
+ status, error2str(status));
+
+ return true;
+}
+
+static bool avrcp_get_total_number_of_items(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint32_t num_of_items;
+ uint16_t uidcounter;
+ uint8_t scope, status, indent = 2;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ if (frame->size < 4) {
+ printf("PDU Malformed\n");
+ packet_hexdump(frame->data, frame->size);
+ return false;
+ }
+
+ if (!l2cap_frame_get_u8(frame, &scope))
+ return false;
+
+ print_field("%*cScope: 0x%02x (%s)", (indent - 8), ' ',
+ scope, scope2str(scope));
+
+ return true;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ',
+ status, error2str(status));
+
+ if (frame->size == 1)
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, &uidcounter))
+ return false;
+
+ print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ',
+ uidcounter, uidcounter);
+
+ if (!l2cap_frame_get_be32(frame, &num_of_items))
+ return false;
+
+ print_field("%*cNumber of Items: 0x%04x (%u)", indent, ' ',
+ num_of_items, num_of_items);
+
+ return true;
+}
+
+static bool avrcp_search_item(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint32_t items;
+ uint16_t charset, namelen, uidcounter;
+ uint8_t status, indent = 2;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ if (frame->size < 4) {
+ printf("PDU Malformed\n");
+ packet_hexdump(frame->data, frame->size);
+ return false;
+ }
+
+ if (!l2cap_frame_get_be16(frame, &charset))
+ return false;
+
+ print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ',
+ charset, charset2str(charset));
+
+ if (!l2cap_frame_get_be16(frame, &namelen))
+ return false;
+
+ print_field("%*cLength: 0x%04x (%u)", indent, ' ', namelen, namelen);
+
+ printf("%*cString: ", indent+8, ' ');
+ for (; namelen > 0; namelen--) {
+ uint8_t c;
+
+ if (!l2cap_frame_get_u8(frame, &c))
+ return false;
+
+ printf("%1c", isprint(c) ? c : '.');
+ }
+
+ printf("\n");
+
+ return true;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ',
+ status, error2str(status));
+
+ if (frame->size == 1)
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, &uidcounter))
+ return false;
+
+ print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ',
+ uidcounter, uidcounter);
+
+ if (!l2cap_frame_get_be32(frame, &items))
+ return false;
+
+ print_field("%*cNumber of Items: 0x%04x (%u)", indent, ' ',
+ items, items);
+
+ return true;
+}
+
+static bool avrcp_get_item_attributes(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint64_t uid;
+ uint16_t uidcounter;
+ uint8_t scope, count, status, indent = 2;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ if (frame->size < 12) {
+ print_field("%*cPDU Malformed", indent, ' ');
+ packet_hexdump(frame->data, frame->size);
+ return false;
+ }
+
+ if (!l2cap_frame_get_u8(frame, &scope))
+ return false;
+
+ print_field("%*cScope: 0x%02x (%s)", indent, ' ',
+ scope, scope2str(scope));
+
+ if (!l2cap_frame_get_be64(frame, &uid))
+ return false;
+
+ print_field("%*cUID: 0x%016" PRIx64 " (%" PRIu64 ")", indent,
+ ' ', uid, uid);
+
+ if (!l2cap_frame_get_be16(frame, &uidcounter))
+ return false;
+
+ print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ',
+ uidcounter, uidcounter);
+
+ if (!l2cap_frame_get_u8(frame, &count))
+ return false;
+
+ print_field("%*cAttributeCount: 0x%02x (%u)", indent, ' ',
+ count, count);
+
+ for (; count > 0; count--) {
+ uint32_t attr;
+
+ if (!l2cap_frame_get_be32(frame, &attr))
+ return false;
+
+ print_field("%*cAttributeID: 0x%08x (%s)", indent, ' ',
+ attr, mediattr2str(attr));
+ }
+
+ return true;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ',
+ status, error2str(status));
+
+ if (frame->size == 1)
+ return false;
+
+ if (!l2cap_frame_get_u8(frame, &count))
+ return false;
+
+ print_field("%*cAttributeCount: 0x%02x (%u)", indent, ' ',
+ count, count);
+
+ if (!avrcp_attribute_entry_list(avctp_frame, indent, count))
+ return false;
+
+ return true;
+}
+
+static bool avrcp_get_folder_items(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint8_t scope, count, status, indent = 2;
+ uint32_t start, end;
+ uint16_t uid, num;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &scope))
+ return false;
+
+ print_field("%*cScope: 0x%02x (%s)", indent, ' ',
+ scope, scope2str(scope));
+
+ if (!l2cap_frame_get_be32(frame, &start))
+ return false;
+
+ print_field("%*cStartItem: 0x%08x (%u)", indent, ' ', start, start);
+
+ if (!l2cap_frame_get_be32(frame, &end))
+ return false;
+
+ print_field("%*cEndItem: 0x%08x (%u)", indent, ' ', end, end);
+
+ if (!l2cap_frame_get_u8(frame, &count))
+ return false;
+
+ print_field("%*cAttributeCount: 0x%02x (%u)", indent, ' ',
+ count, count);
+
+ for (; count > 0; count--) {
+ uint16_t attr;
+
+ if (!l2cap_frame_get_be16(frame, &attr))
+ return false;
+
+ print_field("%*cAttributeID: 0x%08x (%s)", indent, ' ',
+ attr, mediattr2str(attr));
+ }
+
+ return false;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ',
+ status, error2str(status));
+
+ if (!l2cap_frame_get_be16(frame, &uid))
+ return false;
+
+ print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ', uid, uid);
+
+ if (!l2cap_frame_get_be16(frame, &num))
+ return false;
+
+ print_field("%*cNumOfItems: 0x%04x (%u)", indent, ' ', num, num);
+
+ for (; num > 0; num--) {
+ uint8_t type;
+ uint16_t len;
+
+ if (!l2cap_frame_get_u8(frame, &type))
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, &len))
+ return false;
+
+ print_field("%*cItem: 0x%02x (%s) ", indent, ' ',
+ type, type2str(type));
+ print_field("%*cLength: 0x%04x (%u)", indent, ' ', len, len);
+
+ switch (type) {
+ case AVRCP_MEDIA_PLAYER_ITEM_TYPE:
+ avrcp_media_player_item(avctp_frame, indent);
+ break;
+ case AVRCP_FOLDER_ITEM_TYPE:
+ avrcp_folder_item(avctp_frame, indent);
+ break;
+ case AVRCP_MEDIA_ELEMENT_ITEM_TYPE:
+ avrcp_media_element_item(avctp_frame, indent);
+ break;
+ default:
+ print_field("%*cUnknown Media Item type", indent, ' ');
+ packet_hexdump(frame->data, frame->size);
+ break;
+ }
+ }
+ return true;
+}
+
static bool avrcp_set_browsed_player(struct avctp_frame *avctp_frame)
{
struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
@@ -1722,6 +2463,24 @@ static bool avrcp_browsing_packet(struct avctp_frame *avctp_frame)
case AVRCP_SET_BROWSED_PLAYER:
avrcp_set_browsed_player(avctp_frame);
break;
+ case AVRCP_GET_FOLDER_ITEMS:
+ avrcp_get_folder_items(avctp_frame);
+ break;
+ case AVRCP_CHANGE_PATH:
+ avrcp_change_path(avctp_frame);
+ break;
+ case AVRCP_GET_ITEM_ATTRIBUTES:
+ avrcp_get_item_attributes(avctp_frame);
+ break;
+ case AVRCP_GET_TOTAL_NUMBER_OF_ITEMS:
+ avrcp_get_total_number_of_items(avctp_frame);
+ break;
+ case AVRCP_SEARCH:
+ avrcp_search_item(avctp_frame);
+ break;
+ case AVRCP_GENERAL_REJECT:
+ avrcp_general_reject(avctp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
}
diff --git a/monitor/avdtp.c b/monitor/avdtp.c
new file mode 100644
index 00000000..3524faa0
--- /dev/null
+++ b/monitor/avdtp.c
@@ -0,0 +1,787 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "avdtp.h"
+#include "a2dp.h"
+
+/* Message Types */
+#define AVDTP_MSG_TYPE_COMMAND 0x00
+#define AVDTP_MSG_TYPE_GENERAL_REJECT 0x01
+#define AVDTP_MSG_TYPE_RESPONSE_ACCEPT 0x02
+#define AVDTP_MSG_TYPE_RESPONSE_REJECT 0x03
+
+/* Signal Identifiers */
+#define AVDTP_DISCOVER 0x01
+#define AVDTP_GET_CAPABILITIES 0x02
+#define AVDTP_SET_CONFIGURATION 0x03
+#define AVDTP_GET_CONFIGURATION 0x04
+#define AVDTP_RECONFIGURE 0x05
+#define AVDTP_OPEN 0x06
+#define AVDTP_START 0x07
+#define AVDTP_CLOSE 0x08
+#define AVDTP_SUSPEND 0x09
+#define AVDTP_ABORT 0x0a
+#define AVDTP_SECURITY_CONTROL 0x0b
+#define AVDTP_GET_ALL_CAPABILITIES 0x0c
+#define AVDTP_DELAYREPORT 0x0d
+
+/* Service Categories */
+#define AVDTP_MEDIA_TRANSPORT 0x01
+#define AVDTP_REPORTING 0x02
+#define AVDTP_RECOVERY 0x03
+#define AVDTP_CONTENT_PROTECTION 0x04
+#define AVDTP_HEADER_COMPRESSION 0x05
+#define AVDTP_MULTIPLEXING 0x06
+#define AVDTP_MEDIA_CODEC 0x07
+#define AVDTP_DELAY_REPORTING 0x08
+
+struct avdtp_frame {
+ uint8_t hdr;
+ uint8_t sig_id;
+ struct l2cap_frame l2cap_frame;
+};
+
+static inline bool is_configuration_sig_id(uint8_t sig_id)
+{
+ return (sig_id == AVDTP_SET_CONFIGURATION) ||
+ (sig_id == AVDTP_GET_CONFIGURATION) ||
+ (sig_id == AVDTP_RECONFIGURE);
+}
+
+static const char *msgtype2str(uint8_t msgtype)
+{
+ switch (msgtype) {
+ case 0:
+ return "Command";
+ case 1:
+ return "General Reject";
+ case 2:
+ return "Response Accept";
+ case 3:
+ return "Response Reject";
+ }
+
+ return "";
+}
+
+static const char *sigid2str(uint8_t sigid)
+{
+ switch (sigid) {
+ case AVDTP_DISCOVER:
+ return "Discover";
+ case AVDTP_GET_CAPABILITIES:
+ return "Get Capabilities";
+ case AVDTP_SET_CONFIGURATION:
+ return "Set Configuration";
+ case AVDTP_GET_CONFIGURATION:
+ return "Get Configuration";
+ case AVDTP_RECONFIGURE:
+ return "Reconfigure";
+ case AVDTP_OPEN:
+ return "Open";
+ case AVDTP_START:
+ return "Start";
+ case AVDTP_CLOSE:
+ return "Close";
+ case AVDTP_SUSPEND:
+ return "Suspend";
+ case AVDTP_ABORT:
+ return "Abort";
+ case AVDTP_SECURITY_CONTROL:
+ return "Security Control";
+ case AVDTP_GET_ALL_CAPABILITIES:
+ return "Get All Capabilities";
+ case AVDTP_DELAYREPORT:
+ return "Delay Report";
+ default:
+ return "Reserved";
+ }
+}
+
+static const char *error2str(uint8_t error)
+{
+ switch (error) {
+ case 0x01:
+ return "BAD_HEADER_FORMAT";
+ case 0x11:
+ return "BAD_LENGTH";
+ case 0x12:
+ return "BAD_ACP_SEID";
+ case 0x13:
+ return "SEP_IN_USE";
+ case 0x14:
+ return "SEP_NOT_IN_USER";
+ case 0x17:
+ return "BAD_SERV_CATEGORY";
+ case 0x18:
+ return "BAD_PAYLOAD_FORMAT";
+ case 0x19:
+ return "NOT_SUPPORTED_COMMAND";
+ case 0x1a:
+ return "INVALID_CAPABILITIES";
+ case 0x22:
+ return "BAD_RECOVERY_TYPE";
+ case 0x23:
+ return "BAD_MEDIA_TRANSPORT_FORMAT";
+ case 0x25:
+ return "BAD_RECOVERY_FORMAT";
+ case 0x26:
+ return "BAD_ROHC_FORMAT";
+ case 0x27:
+ return "BAD_CP_FORMAT";
+ case 0x28:
+ return "BAD_MULTIPLEXING_FORMAT";
+ case 0x29:
+ return "UNSUPPORTED_CONFIGURATION";
+ case 0x31:
+ return "BAD_STATE";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *mediatype2str(uint8_t media_type)
+{
+ switch (media_type) {
+ case 0x00:
+ return "Audio";
+ case 0x01:
+ return "Video";
+ case 0x02:
+ return "Multimedia";
+ default:
+ return "Reserved";
+ }
+}
+
+static const char *mediacodec2str(uint8_t codec)
+{
+ switch (codec) {
+ case 0x00:
+ return "SBC";
+ case 0x01:
+ return "MPEG-1,2 Audio";
+ case 0x02:
+ return "MPEG-2,4 AAC";
+ case 0x04:
+ return "ATRAC Family";
+ case 0xff:
+ return "Non-A2DP";
+ default:
+ return "Reserved";
+ }
+}
+
+static const char *cptype2str(uint8_t cp)
+{
+ switch (cp) {
+ case 0x0001:
+ return "DTCP";
+ case 0x0002:
+ return "SCMS-T";
+ default:
+ return "Reserved";
+ }
+}
+
+static const char *servicecat2str(uint8_t service_cat)
+{
+ switch (service_cat) {
+ case AVDTP_MEDIA_TRANSPORT:
+ return "Media Transport";
+ case AVDTP_REPORTING:
+ return "Reporting";
+ case AVDTP_RECOVERY:
+ return "Recovery";
+ case AVDTP_CONTENT_PROTECTION:
+ return "Content Protection";
+ case AVDTP_HEADER_COMPRESSION:
+ return "Header Compression";
+ case AVDTP_MULTIPLEXING:
+ return "Multiplexing";
+ case AVDTP_MEDIA_CODEC:
+ return "Media Codec";
+ case AVDTP_DELAY_REPORTING:
+ return "Delay Reporting";
+ default:
+ return "Reserved";
+ }
+}
+
+static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t error;
+
+ if (!l2cap_frame_get_u8(frame, &error))
+ return false;
+
+ print_field("Error code: %s (0x%02x)", error2str(error), error);
+
+ return true;
+}
+
+static bool service_content_protection(struct avdtp_frame *avdtp_frame,
+ uint8_t losc)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint16_t type = 0;
+
+ if (losc < 2)
+ return false;
+
+ if (!l2cap_frame_get_le16(frame, &type))
+ return false;
+
+ losc -= 2;
+
+ print_field("%*cContent Protection Type: %s (0x%04x)", 2, ' ',
+ cptype2str(type), type);
+
+ /* TODO: decode protection specific information */
+ packet_hexdump(frame->data, losc);
+
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
+static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = 0;
+ uint8_t codec = 0;
+
+ if (losc < 2)
+ return false;
+
+ l2cap_frame_get_u8(frame, &type);
+ l2cap_frame_get_u8(frame, &codec);
+
+ losc -= 2;
+
+ print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
+ mediatype2str(type >> 4), type >> 4);
+
+ print_field("%*cMedia Codec: %s (0x%02x)", 2, ' ',
+ mediacodec2str(codec), codec);
+
+ if (is_configuration_sig_id(avdtp_frame->sig_id))
+ return a2dp_codec_cfg(codec, losc, frame);
+ else
+ return a2dp_codec_cap(codec, losc, frame);
+}
+
+static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t service_cat;
+ uint8_t losc;
+
+ while (l2cap_frame_get_u8(frame, &service_cat)) {
+ print_field("Service Category: %s (0x%02x)",
+ servicecat2str(service_cat), service_cat);
+
+ if (!l2cap_frame_get_u8(frame, &losc))
+ return false;
+
+ if (frame->size < losc)
+ return false;
+
+ switch (service_cat) {
+ case AVDTP_CONTENT_PROTECTION:
+ if (!service_content_protection(avdtp_frame, losc))
+ return false;
+ break;
+ case AVDTP_MEDIA_CODEC:
+ if (!service_media_codec(avdtp_frame, losc))
+ return false;
+ break;
+ case AVDTP_MEDIA_TRANSPORT:
+ case AVDTP_REPORTING:
+ case AVDTP_RECOVERY:
+ case AVDTP_HEADER_COMPRESSION:
+ case AVDTP_MULTIPLEXING:
+ case AVDTP_DELAY_REPORTING:
+ default:
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ }
+
+ }
+
+ return true;
+}
+
+static bool avdtp_discover(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+ uint8_t info;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ while (l2cap_frame_get_u8(frame, &seid)) {
+ print_field("ACP SEID: %d", seid >> 2);
+
+ if (!l2cap_frame_get_u8(frame, &info))
+ return false;
+
+ print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
+ mediatype2str(info >> 4), info >> 4);
+ print_field("%*cSEP Type: %s (0x%02x)", 2, ' ',
+ info & 0x04 ? "SNK" : "SRC",
+ (info >> 3) & 0x01);
+ print_field("%*cIn use: %s", 2, ' ',
+ seid & 0x02 ? "Yes" : "No");
+ }
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_get_capabilities(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_set_configuration(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t acp_seid, int_seid;
+ uint8_t service_cat;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &acp_seid))
+ return false;
+
+ print_field("ACP SEID: %d", acp_seid >> 2);
+
+ if (!l2cap_frame_get_u8(frame, &int_seid))
+ return false;
+
+ print_field("INT SEID: %d", int_seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ return false;
+
+ print_field("Service Category: %s (0x%02x)",
+ servicecat2str(service_cat), service_cat);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_get_configuration(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_reconfigure(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+ uint8_t service_cat;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ return false;
+
+ print_field("Service Category: %s (0x%02x)",
+ servicecat2str(service_cat), service_cat);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_open(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_start(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ while (l2cap_frame_get_u8(frame, &seid))
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_close(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_suspend(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ while (l2cap_frame_get_u8(frame, &seid))
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_abort(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ }
+
+ return false;
+}
+
+static bool avdtp_security_control(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ /* TODO: decode more information */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ /* TODO: decode more information */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_delayreport(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+ uint16_t delay;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ if (!l2cap_frame_get_be16(frame, &delay))
+ return false;
+
+ print_field("Delay: %d.%dms", delay / 10, delay % 10);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
+static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ const char *pdu_color;
+ uint8_t hdr;
+ uint8_t sig_id;
+ uint8_t nosp = 0;
+
+ if (frame->in)
+ pdu_color = COLOR_MAGENTA;
+ else
+ pdu_color = COLOR_BLUE;
+
+ if (!l2cap_frame_get_u8(frame, &hdr))
+ return false;
+
+ avdtp_frame->hdr = hdr;
+
+ /* Continue Packet || End Packet */
+ if (((hdr & 0x0c) == 0x08) || ((hdr & 0x0c) == 0x0c)) {
+ /* TODO: handle fragmentation */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ }
+
+ /* Start Packet */
+ if ((hdr & 0x0c) == 0x04) {
+ if (!l2cap_frame_get_u8(frame, &nosp))
+ return false;
+ }
+
+ if (!l2cap_frame_get_u8(frame, &sig_id))
+ return false;
+
+ sig_id &= 0x3f;
+
+ avdtp_frame->sig_id = sig_id;
+
+ print_indent(6, pdu_color, "AVDTP: ", sigid2str(sig_id), COLOR_OFF,
+ " (0x%02x) %s (0x%02x) type 0x%02x label %d nosp %d",
+ sig_id, msgtype2str(hdr & 0x03), hdr & 0x03,
+ hdr & 0x0c, hdr >> 4, nosp);
+
+ /* Start Packet */
+ if ((hdr & 0x0c) == 0x04) {
+ /* TODO: handle fragmentation */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ }
+
+ /* General Reject */
+ if ((hdr & 0x03) == 0x03)
+ return true;
+
+ switch (sig_id) {
+ case AVDTP_DISCOVER:
+ return avdtp_discover(avdtp_frame);
+ case AVDTP_GET_CAPABILITIES:
+ case AVDTP_GET_ALL_CAPABILITIES:
+ return avdtp_get_capabilities(avdtp_frame);
+ case AVDTP_SET_CONFIGURATION:
+ return avdtp_set_configuration(avdtp_frame);
+ case AVDTP_GET_CONFIGURATION:
+ return avdtp_get_configuration(avdtp_frame);
+ case AVDTP_RECONFIGURE:
+ return avdtp_reconfigure(avdtp_frame);
+ case AVDTP_OPEN:
+ return avdtp_open(avdtp_frame);
+ case AVDTP_START:
+ return avdtp_start(avdtp_frame);
+ case AVDTP_CLOSE:
+ return avdtp_close(avdtp_frame);
+ case AVDTP_SUSPEND:
+ return avdtp_suspend(avdtp_frame);
+ case AVDTP_ABORT:
+ return avdtp_abort(avdtp_frame);
+ case AVDTP_SECURITY_CONTROL:
+ return avdtp_security_control(avdtp_frame);
+ case AVDTP_DELAYREPORT:
+ return avdtp_delayreport(avdtp_frame);
+ }
+
+ packet_hexdump(frame->data, frame->size);
+
+ return true;
+}
+
+void avdtp_packet(const struct l2cap_frame *frame)
+{
+ struct avdtp_frame avdtp_frame;
+ bool ret;
+
+ l2cap_frame_pull(&avdtp_frame.l2cap_frame, frame, 0);
+
+ switch (frame->seq_num) {
+ case 1:
+ ret = avdtp_signalling_packet(&avdtp_frame);
+ break;
+ default:
+ packet_hexdump(frame->data, frame->size);
+ return;
+ }
+
+ if (!ret) {
+ print_text(COLOR_ERROR, "PDU malformed");
+ packet_hexdump(frame->data, frame->size);
+ }
+}
diff --git a/monitor/avdtp.h b/monitor/avdtp.h
new file mode 100644
index 00000000..f77d82ee
--- /dev/null
+++ b/monitor/avdtp.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void avdtp_packet(const struct l2cap_frame *frame);
diff --git a/monitor/bnep.c b/monitor/bnep.c
new file mode 100644
index 00000000..01392e8e
--- /dev/null
+++ b/monitor/bnep.c
@@ -0,0 +1,482 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "uuid.h"
+#include "keys.h"
+#include "sdp.h"
+#include "bnep.h"
+
+#define GET_PKT_TYPE(type) (type & 0x7f)
+#define GET_EXTENSION(type) (type & 0x80)
+
+/* BNEP Extension Type */
+#define BNEP_EXTENSION_CONTROL 0x00
+
+#define BNEP_CONTROL 0x01
+
+uint16_t proto = 0x0000;
+
+struct bnep_frame {
+ uint8_t type;
+ int extension;
+ struct l2cap_frame l2cap_frame;
+};
+
+static bool get_macaddr(struct bnep_frame *bnep_frame, char *str)
+{
+ uint8_t addr[6];
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (!l2cap_frame_get_u8(frame, &addr[i]))
+ return false;
+
+ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+ return true;
+}
+
+static bool bnep_general(struct bnep_frame *bnep_frame,
+ uint8_t indent, int hdr_len)
+{
+ struct l2cap_frame *frame;
+ char src_addr[20], dest_addr[20];
+
+ if (!get_macaddr(bnep_frame, dest_addr))
+ return false;
+
+ if (!get_macaddr(bnep_frame, src_addr))
+ return false;
+
+ frame = &bnep_frame->l2cap_frame;
+
+ if (!l2cap_frame_get_be16(frame, &proto))
+ return false;
+
+ print_field("%*cdst %s src %s [proto 0x%04x] ", indent,
+ ' ', dest_addr, src_addr, proto);
+
+ return true;
+
+}
+
+static bool cmd_nt_understood(struct bnep_frame *bnep_frame, uint8_t indent)
+{
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ uint8_t ptype;
+
+ if (!l2cap_frame_get_u8(frame, &ptype))
+ return false;
+
+ print_field("%*cType: 0x%02x ", indent, ' ', ptype);
+
+ return true;
+}
+
+static bool setup_conn_req(struct bnep_frame *bnep_frame, uint8_t indent)
+{
+
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ uint8_t uuid_size;
+ uint32_t src_uuid = 0, dst_uuid = 0;
+
+ if (!l2cap_frame_get_u8(frame, &uuid_size))
+ return false;
+
+ print_field("%*cSize: 0x%02x ", indent, ' ', uuid_size);
+
+ switch (uuid_size) {
+ case 2:
+ if (!l2cap_frame_get_be16(frame, (uint16_t *) &dst_uuid))
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, (uint16_t *) &src_uuid))
+ return false;
+ break;
+ case 4:
+ if (!l2cap_frame_get_be32(frame, &dst_uuid))
+ return false;
+
+ if (!l2cap_frame_get_be32(frame, &src_uuid))
+ return false;
+ break;
+ case 16:
+ if (!l2cap_frame_get_be32(frame, &dst_uuid))
+ return false;
+
+ l2cap_frame_pull(frame, frame, 12);
+
+ if (!l2cap_frame_get_be32(frame, &src_uuid))
+ return false;
+
+ l2cap_frame_pull(frame, frame, 12);
+ break;
+ default:
+ l2cap_frame_pull(frame, frame, (uuid_size * 2));
+ return true;
+ }
+
+ print_field("%*cDst: 0x%x(%s)", indent, ' ', dst_uuid,
+ uuid32_to_str(dst_uuid));
+ print_field("%*cSrc: 0x%x(%s)", indent, ' ', src_uuid,
+ uuid32_to_str(src_uuid));
+ return true;
+}
+
+static const char *value2str(uint16_t value)
+{
+ switch (value) {
+ case 0x00:
+ return "Operation Successful";
+ case 0x01:
+ return "Operation Failed - Invalid Dst Srv UUID";
+ case 0x02:
+ return "Operation Failed - Invalid Src Srv UUID";
+ case 0x03:
+ return "Operation Failed - Invalid Srv UUID size";
+ case 0x04:
+ return "Operation Failed - Conn not allowed";
+ default:
+ return "Unknown";
+ }
+}
+
+static bool print_rsp_msg(struct bnep_frame *bnep_frame, uint8_t indent)
+{
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ uint16_t rsp_msg;
+
+ if (!l2cap_frame_get_be16(frame, &rsp_msg))
+ return false;
+
+ print_field("%*cRsp msg: %s(0x%04x) ", indent, ' ',
+ value2str(rsp_msg), rsp_msg);
+
+ return true;
+}
+
+static bool filter_nettype_req(struct bnep_frame *bnep_frame, uint8_t indent)
+{
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ uint16_t length, start_range, end_range;
+ int i;
+
+ if (!l2cap_frame_get_be16(frame, &length))
+ return false;
+
+ print_field("%*cLength: 0x%04x", indent, ' ', length);
+
+ for (i = 0; i < length / 4; i++) {
+
+ if (!l2cap_frame_get_be16(frame, &start_range))
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, &end_range))
+ return false;
+
+ print_field("%*c0x%04x - 0x%04x", indent, ' ',
+ start_range, end_range);
+ }
+
+ return true;
+}
+
+static bool filter_multaddr_req(struct bnep_frame *bnep_frame, uint8_t indent)
+{
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ uint16_t length;
+ char start_addr[20], end_addr[20];
+ int i;
+
+ if (!l2cap_frame_get_be16(frame, &length))
+ return false;
+
+ print_field("%*cLength: 0x%04x", indent, ' ', length);
+
+ for (i = 0; i < length / 12; i++) {
+
+ if (!get_macaddr(bnep_frame, start_addr))
+ return false;
+
+ if (!get_macaddr(bnep_frame, end_addr))
+ return false;
+
+ print_field("%*c%s - %s", indent, ' ', start_addr, end_addr);
+ }
+
+ return true;
+}
+
+struct bnep_control_data {
+ uint8_t type;
+ const char *str;
+ bool (*func) (struct bnep_frame *frame, uint8_t indent);
+};
+
+static const struct bnep_control_data bnep_control_table[] = {
+ { 0x00, "Command Not Understood", cmd_nt_understood },
+ { 0x01, "Setup Conn Req", setup_conn_req },
+ { 0x02, "Setup Conn Rsp", print_rsp_msg },
+ { 0x03, "Filter NetType Set", filter_nettype_req },
+ { 0x04, "Filter NetType Rsp", print_rsp_msg },
+ { 0x05, "Filter MultAddr Set", filter_multaddr_req },
+ { 0x06, "Filter MultAddr Rsp", print_rsp_msg },
+ { }
+};
+
+static bool bnep_control(struct bnep_frame *bnep_frame,
+ uint8_t indent, int hdr_len)
+{
+ uint8_t ctype;
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ const struct bnep_control_data *bnep_control_data = NULL;
+ const char *type_str;
+ int i;
+
+ if (!l2cap_frame_get_u8(frame, &ctype))
+ return false;
+
+ for (i = 0; bnep_control_table[i].str; i++) {
+ if (bnep_control_table[i].type == ctype) {
+ bnep_control_data = &bnep_control_table[i];
+ break;
+ }
+ }
+
+ if (bnep_control_data)
+ type_str = bnep_control_data->str;
+ else
+ type_str = "Unknown control type";
+
+ print_field("%*c%s (0x%02x) ", indent, ' ', type_str, ctype);
+
+ if (!bnep_control_data || !bnep_control_data->func) {
+ packet_hexdump(frame->data, hdr_len - 1);
+ l2cap_frame_pull(frame, frame, hdr_len - 1);
+ goto done;
+ }
+
+ if (!bnep_control_data->func(bnep_frame, indent+2))
+ return false;
+
+done:
+ return true;
+}
+
+static bool bnep_compressed(struct bnep_frame *bnep_frame,
+ uint8_t indent, int hdr_len)
+{
+
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+
+ if (!l2cap_frame_get_be16(frame, &proto))
+ return false;
+
+ print_field("%*c[proto 0x%04x] ", indent, ' ', proto);
+
+ return true;
+}
+
+static bool bnep_src_only(struct bnep_frame *bnep_frame,
+ uint8_t indent, int hdr_len)
+{
+
+ struct l2cap_frame *frame;
+ char src_addr[20];
+
+ if (!get_macaddr(bnep_frame, src_addr))
+ return false;
+
+ frame = &bnep_frame->l2cap_frame;
+
+ if (!l2cap_frame_get_be16(frame, &proto))
+ return false;
+
+ print_field("%*csrc %s [proto 0x%04x] ", indent,
+ ' ', src_addr, proto);
+
+ return true;
+}
+
+static bool bnep_dst_only(struct bnep_frame *bnep_frame,
+ uint8_t indent, int hdr_len)
+{
+
+ struct l2cap_frame *frame;
+ char dest_addr[20];
+
+ if (!get_macaddr(bnep_frame, dest_addr))
+ return false;
+
+ frame = &bnep_frame->l2cap_frame;
+
+ if (!l2cap_frame_get_be16(frame, &proto))
+ return false;
+
+ print_field("%*cdst %s [proto 0x%04x] ", indent,
+ ' ', dest_addr, proto);
+
+ return true;
+}
+
+static bool bnep_eval_extension(struct bnep_frame *bnep_frame, uint8_t indent)
+{
+ struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
+ uint8_t type, length;
+ int extension;
+
+ if (!l2cap_frame_get_u8(frame, &type))
+ return false;
+
+ if (!l2cap_frame_get_u8(frame, &length))
+ return false;
+
+ extension = GET_EXTENSION(type);
+ type = GET_PKT_TYPE(type);
+
+ switch (type) {
+ case BNEP_EXTENSION_CONTROL:
+ print_field("%*cExt Control(0x%02x|%s) len 0x%02x", indent,
+ ' ', type, extension ? "1" : "0", length);
+ if (!bnep_control(bnep_frame, indent+2, length))
+ return false;
+ break;
+
+ default:
+ print_field("%*cExt Unknown(0x%02x|%s) len 0x%02x", indent,
+ ' ', type, extension ? "1" : "0", length);
+ packet_hexdump(frame->data, length);
+ l2cap_frame_pull(frame, frame, length);
+ }
+
+ if (extension)
+ if (!bnep_eval_extension(bnep_frame, indent))
+ return false;
+
+ return true;
+}
+
+struct bnep_data {
+ uint8_t type;
+ const char *str;
+ bool (*func) (struct bnep_frame *frame, uint8_t indent, int hdr_len);
+};
+
+static const struct bnep_data bnep_table[] = {
+ { 0x00, "General Ethernet", bnep_general },
+ { 0x01, "Control", bnep_control },
+ { 0x02, "Compressed Ethernet", bnep_compressed },
+ { 0x03, "Compressed Ethernet SrcOnly", bnep_src_only },
+ { 0x04, "Compressed Ethernet DestOnly", bnep_dst_only },
+ { }
+};
+
+void bnep_packet(const struct l2cap_frame *frame)
+{
+ uint8_t type, indent = 1;
+ struct bnep_frame bnep_frame;
+ struct l2cap_frame *l2cap_frame;
+ const struct bnep_data *bnep_data = NULL;
+ const char *pdu_color, *pdu_str;
+ int i;
+
+ l2cap_frame_pull(&bnep_frame.l2cap_frame, frame, 0);
+ l2cap_frame = &bnep_frame.l2cap_frame;
+
+ if (!l2cap_frame_get_u8(l2cap_frame, &type))
+ goto fail;
+
+ bnep_frame.extension = GET_EXTENSION(type);
+ bnep_frame.type = GET_PKT_TYPE(type);
+
+ for (i = 0; bnep_table[i].str; i++) {
+ if (bnep_table[i].type == bnep_frame.type) {
+ bnep_data = &bnep_table[i];
+ break;
+ }
+ }
+
+ if (bnep_data) {
+ if (bnep_data->func) {
+ if (frame->in)
+ pdu_color = COLOR_MAGENTA;
+ else
+ pdu_color = COLOR_BLUE;
+ } else
+ pdu_color = COLOR_WHITE_BG;
+ pdu_str = bnep_data->str;
+ } else {
+ pdu_color = COLOR_WHITE_BG;
+ pdu_str = "Unknown packet type";
+ }
+
+ print_indent(6, pdu_color, "BNEP: ", pdu_str, COLOR_OFF,
+ " (0x%02x|%s)", bnep_frame.type,
+ bnep_frame.extension ? "1" : "0");
+
+ if (!bnep_data || !bnep_data->func) {
+ packet_hexdump(l2cap_frame->data, l2cap_frame->size);
+ return;
+ }
+
+ if (!bnep_data->func(&bnep_frame, indent, -1))
+ goto fail;
+
+ /* Extension info */
+ if (bnep_frame.extension)
+ if (!bnep_eval_extension(&bnep_frame, indent+2))
+ goto fail;
+
+ /* Control packet => No payload info */
+ if (bnep_frame.type == BNEP_CONTROL)
+ return;
+
+ /* TODO: Handle BNEP IP packet */
+ packet_hexdump(l2cap_frame->data, l2cap_frame->size);
+
+ return;
+
+fail:
+ print_text(COLOR_ERROR, "frame too short");
+ packet_hexdump(frame->data, frame->size);
+}
diff --git a/monitor/bnep.h b/monitor/bnep.h
new file mode 100644
index 00000000..38340d6c
--- /dev/null
+++ b/monitor/bnep.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void bnep_packet(const struct l2cap_frame *frame);
diff --git a/monitor/broadcom.c b/monitor/broadcom.c
new file mode 100644
index 00000000..a3c34439
--- /dev/null
+++ b/monitor/broadcom.c
@@ -0,0 +1,251 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "src/shared/util.h"
+#include "display.h"
+#include "packet.h"
+#include "lmp.h"
+#include "ll.h"
+#include "vendor.h"
+#include "broadcom.h"
+
+static void print_status(uint8_t status)
+{
+ packet_print_error("Status", status);
+}
+
+static void null_cmd(const void *data, uint8_t size)
+{
+}
+
+static void status_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+
+ print_status(status);
+}
+
+static void write_bd_addr_cmd(const void *data, uint8_t size)
+{
+ packet_print_addr("Address", data, false);
+}
+
+static void enable_usb_hid_emulation_cmd(const void *data, uint8_t size)
+{
+ uint8_t enable = get_u8(data);
+ const char *str;
+
+ switch (enable) {
+ case 0x00:
+ str = "Bluetooth mode";
+ break;
+ case 0x01:
+ str = "HID Mode";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Enable: %s (0x%2.2x)", str, enable);
+}
+
+static void write_ram_cmd(const void *data, uint8_t size)
+{
+ uint32_t addr = get_le32(data);
+
+ print_field("Address: 0x%8.8x", addr);
+
+ packet_hexdump(data + 4, size - 4);
+}
+
+static void launch_ram_cmd(const void *data, uint8_t size)
+{
+ uint32_t addr = get_le32(data);
+
+ print_field("Address: 0x%8.8x", addr);
+}
+
+static void read_vid_pid_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+ uint16_t vid = get_le16(data + 1);
+ uint16_t pid = get_le16(data + 3);
+
+ print_status(status);
+ print_field("Product: %4.4x:%4.4x", vid, pid);
+}
+
+static void read_verbose_version_info_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+ uint8_t chip_id = get_u8(data + 1);
+ uint8_t target_id = get_u8(data + 2);
+ uint16_t build_base = get_le16(data + 3);
+ uint16_t build_num = get_le16(data + 5);
+ const char *str;
+
+ print_status(status);
+ print_field("Chip ID: %u (0x%2.2x)", chip_id, chip_id);
+
+ switch (target_id) {
+ case 254:
+ str = "Invalid";
+ break;
+ case 255:
+ str = "Undefined";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Build target: %s (%u)", str, target_id);
+ print_field("Build baseline: %u (0x%4.4x)", build_base, build_base);
+ print_field("Build number: %u (0x%4.4x)", build_num, build_num);
+}
+
+static const struct vendor_ocf vendor_ocf_table[] = {
+ { 0x001, "Write BD ADDR",
+ write_bd_addr_cmd, 6, true,
+ status_rsp, 1, true },
+ { 0x018, "Update UART Baud Rate" },
+ { 0x027, "Set Sleepmode Param" },
+ { 0x02e, "Download Minidriver",
+ null_cmd, 0, true,
+ status_rsp, 1, true },
+ { 0x03b, "Enable USB HID Emulation",
+ enable_usb_hid_emulation_cmd, 1, true,
+ status_rsp, 1, true },
+ { 0x045, "Write UART Clock Setting" },
+ { 0x04c, "Write RAM",
+ write_ram_cmd, 4, false,
+ status_rsp, 1, true },
+ { 0x04e, "Launch RAM",
+ launch_ram_cmd, 4, true,
+ status_rsp, 1, true },
+ { 0x05a, "Read VID PID",
+ null_cmd, 0, true,
+ read_vid_pid_rsp, 5, true },
+ { 0x079, "Read Verbose Config Version Info",
+ null_cmd, 0, true,
+ read_verbose_version_info_rsp, 7, true },
+ { }
+};
+
+const struct vendor_ocf *broadcom_vendor_ocf(uint16_t ocf)
+{
+ int i;
+
+ for (i = 0; vendor_ocf_table[i].str; i++) {
+ if (vendor_ocf_table[i].ocf == ocf)
+ return &vendor_ocf_table[i];
+ }
+
+ return NULL;
+}
+
+void broadcom_lm_diag(const void *data, uint8_t size)
+{
+ uint8_t type;
+ uint32_t clock;
+ const uint8_t *addr;
+ const char *str;
+
+ if (size != 63) {
+ packet_hexdump(data, size);
+ return;
+ }
+
+ type = *((uint8_t *) data);
+ clock = get_be32(data + 1);
+
+ switch (type) {
+ case 0x00:
+ str = "LMP sent";
+ break;
+ case 0x01:
+ str = "LMP receive";
+ break;
+ case 0x80:
+ str = "LL sent";
+ break;
+ case 0x81:
+ str = "LL receive";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ print_field("Type: %s (%u)", str, type);
+ print_field("Clock: 0x%8.8x", clock);
+
+ switch (type) {
+ case 0x00:
+ addr = data + 5;
+ print_field("Address: --:--:%2.2X:%2.2X:%2.2X:%2.2X",
+ addr[0], addr[1], addr[2], addr[3]);
+ packet_hexdump(data + 9, 1);
+ lmp_packet(data + 10, size - 10, true);
+ break;
+ case 0x01:
+ addr = data + 5;
+ print_field("Address: --:--:%2.2X:%2.2X:%2.2X:%2.2X",
+ addr[0], addr[1], addr[2], addr[3]);
+ packet_hexdump(data + 9, 4);
+ lmp_packet(data + 13, size - 13, true);
+ break;
+ case 0x80:
+ case 0x81:
+ packet_hexdump(data + 5, 7);
+ llcp_packet(data + 12, size - 12, true);
+ break;
+ default:
+ packet_hexdump(data + 9, size - 9);
+ break;
+ }
+}
+
+static const struct vendor_evt vendor_evt_table[] = {
+ { }
+};
+
+const struct vendor_evt *broadcom_vendor_evt(uint8_t evt)
+{
+ int i;
+
+ for (i = 0; vendor_evt_table[i].str; i++) {
+ if (vendor_evt_table[i].evt == evt)
+ return &vendor_evt_table[i];
+ }
+
+ return NULL;
+}
diff --git a/monitor/broadcom.h b/monitor/broadcom.h
new file mode 100644
index 00000000..ceda0e18
--- /dev/null
+++ b/monitor/broadcom.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+struct vendor_ocf;
+struct vendor_evt;
+
+const struct vendor_ocf *broadcom_vendor_ocf(uint16_t ocf);
+const struct vendor_evt *broadcom_vendor_evt(uint8_t evt);
+void broadcom_lm_diag(const void *data, uint8_t size);
diff --git a/monitor/bt.h b/monitor/bt.h
index 0d2a15a4..1a21592e 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -99,8 +99,43 @@ struct bt_ll_reject_ind {
uint8_t error;
} __attribute__ ((packed));
+#define BT_LL_SLAVE_FEATURE_REQ 0x0e
+struct bt_ll_slave_feature_req {
+ uint8_t features[8];
+} __attribute__ ((packed));
+
+#define BT_LL_CONN_PARAM_REQ 0x0f
+
+#define BT_LL_CONN_PARAM_RSP 0x10
+
+#define BT_LL_REJECT_IND_EXT 0x11
+struct bt_ll_reject_ind_ext {
+ uint8_t opcode;
+ uint8_t error;
+} __attribute__ ((packed));
+
+#define BT_LL_PING_REQ 0x12
+
+#define BT_LL_PING_RSP 0x13
+
+#define BT_LL_LENGTH_REQ 0x14
+
+#define BT_LL_LENGTH_RSP 0x15
+
#define LMP_ESC4(x) ((127 << 8) | (x))
+#define BT_LMP_NAME_REQ 1
+struct bt_lmp_name_req {
+ uint8_t offset;
+} __attribute__ ((packed));
+
+#define BT_LMP_NAME_RSP 2
+struct bt_lmp_name_rsp {
+ uint8_t offset;
+ uint8_t length;
+ uint8_t fragment[14];
+} __attribute__ ((packed));
+
#define BT_LMP_ACCEPTED 3
struct bt_lmp_accepted {
uint8_t opcode;
@@ -114,6 +149,11 @@ struct bt_lmp_not_accepted {
#define BT_LMP_CLKOFFSET_REQ 5
+#define BT_LMP_CLKOFFSET_RSP 6
+struct bt_lmp_clkoffset_rsp {
+ uint16_t offset;
+} __attribute__ ((packed));
+
#define BT_LMP_DETACH 7
struct bt_lmp_detach {
uint8_t error;
@@ -146,6 +186,11 @@ struct bt_lmp_start_encryption_req {
#define BT_LMP_STOP_ENCRYPTION_REQ 18
+#define BT_LMP_SWITCH_REQ 19
+struct bt_lmp_switch_req {
+ uint32_t instant;
+} __attribute__ ((packed));
+
#define BT_LMP_UNSNIFF_REQ 24
#define BT_LMP_MAX_POWER 33
@@ -154,6 +199,11 @@ struct bt_lmp_start_encryption_req {
#define BT_LMP_AUTO_RATE 35
+#define BT_LMP_PREFERRED_RATE 36
+struct bt_lmp_preferred_rate {
+ uint8_t rate;
+} __attribute__ ((packed));
+
#define BT_LMP_VERSION_REQ 37
struct bt_lmp_version_req {
uint8_t version;
@@ -202,6 +252,12 @@ struct bt_lmp_timing_accuracy_res {
#define BT_LMP_HOST_CONNECTION_REQ 51
+#define BT_LMP_SLOT_OFFSET 52
+struct bt_lmp_slot_offset {
+ uint16_t offset;
+ uint8_t bdaddr[6];
+} __attribute__ ((packed));
+
#define BT_LMP_PAGE_SCAN_MODE_REQ 54
struct bt_lmp_page_scan_mode_req {
uint8_t scheme;
@@ -2224,6 +2280,10 @@ struct bt_hci_evt_mode_change {
} __attribute__ ((packed));
#define BT_HCI_EVT_RETURN_LINK_KEYS 0x15
+struct bt_hci_evt_return_link_keys {
+ uint8_t num_keys;
+ uint8_t keys[0];
+} __attribute__ ((packed));
#define BT_HCI_EVT_PIN_CODE_REQUEST 0x16
struct bt_hci_evt_pin_code_request {
diff --git a/monitor/btsnoop.c b/monitor/btsnoop.c
deleted file mode 100644
index 35005ffa..00000000
--- a/monitor/btsnoop.c
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2014 Intel Corporation
- * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <arpa/inet.h>
-
-#include "lib/bluetooth.h"
-#include "lib/hci.h"
-
-#include "btsnoop.h"
-
-struct btsnoop_hdr {
- uint8_t id[8]; /* Identification Pattern */
- uint32_t version; /* Version Number = 1 */
- uint32_t type; /* Datalink Type */
-} __attribute__ ((packed));
-#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
-
-struct btsnoop_pkt {
- uint32_t size; /* Original Length */
- uint32_t len; /* Included Length */
- uint32_t flags; /* Packet Flags */
- uint32_t drops; /* Cumulative Drops */
- uint64_t ts; /* Timestamp microseconds */
- uint8_t data[0]; /* Packet Data */
-} __attribute__ ((packed));
-#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
-
-static const uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e,
- 0x6f, 0x6f, 0x70, 0x00 };
-
-static const uint32_t btsnoop_version = 1;
-static uint32_t btsnoop_type = 0;
-
-static int btsnoop_fd = -1;
-static uint16_t btsnoop_index = 0xffff;
-
-#ifdef __TIZEN_PATCH__
-static char *btsnoop_path = NULL;
-static int16_t btsnoop_rotate = -1;
-static ssize_t btsnoop_size = -1;
-
-void btsnoop_create(const char *path, uint32_t type,
- int16_t rotate_count, ssize_t file_size)
-#else
-void btsnoop_create(const char *path, uint32_t type)
-#endif
-{
- struct btsnoop_hdr hdr;
- ssize_t written;
-
- if (btsnoop_fd >= 0)
- return;
-
- btsnoop_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (btsnoop_fd < 0)
- return;
-
- btsnoop_type = type;
-
- memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
- hdr.version = htobe32(btsnoop_version);
- hdr.type = htobe32(btsnoop_type);
-
- written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
- if (written < 0) {
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return;
- }
-
-#ifdef __TIZEN_PATCH__
- if (rotate_count > 0 && file_size > 0) {
- btsnoop_path = strdup(path);
- btsnoop_rotate = rotate_count;
- btsnoop_size = file_size;
- }
-#endif
-}
-
-#ifdef __TIZEN_PATCH__
-static void btsnoop_create_2(void)
-{
- struct btsnoop_hdr hdr;
- ssize_t written;
-
- if (btsnoop_fd >= 0)
- close(btsnoop_fd);
-
- btsnoop_fd = open(btsnoop_path,
- O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (btsnoop_fd < 0)
- goto fail;
-
- memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
- hdr.version = htobe32(btsnoop_version);
- hdr.type = htobe32(btsnoop_type);
-
- written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
- if (written < 0) {
- close(btsnoop_fd);
- btsnoop_fd = -1;
- goto fail;
- }
-
- return;
-
-fail:
- free(btsnoop_path);
- btsnoop_rotate = -1;
- btsnoop_size = -1;
- btsnoop_index = 0xffff;
-
- return;
-}
-
-static void btsnoop_rotate_files(void)
-{
- char *filename = NULL;
- char *new_filename = NULL;
- int i;
- int postfix_width = 0;
- int err;
-
- if (btsnoop_rotate <= 1)
- return;
-
- for (i = btsnoop_rotate / 10; i; i /= 10)
- postfix_width++;
-
- for (i = btsnoop_rotate - 2; i >= 0; i--) {
- if (i == 0) {
- filename = strdup(btsnoop_path);
- err = (filename == NULL) ? -1 : 0;
- } else {
- err = asprintf(&filename, "%s.%0*d",
- btsnoop_path, postfix_width, i);
- }
-
- if (err < 0 || access(filename, F_OK) < 0)
- goto done;
-
- err = asprintf(&new_filename, "%s.%0*d",
- btsnoop_path, postfix_width, i + 1);
- if (err < 0)
- goto done;
-
- err = rename(filename, new_filename)
-
-done:
- if (new_filename) {
- free(new_filename);
- new_filename = NULL;
- }
-
- if (filename) {
- free(filename);
- filename = NULL;
- }
-
- if (err < 0)
- break;
- }
-}
-#endif
-
-void btsnoop_write(struct timeval *tv, uint32_t flags,
- const void *data, uint16_t size)
-{
- struct btsnoop_pkt pkt;
- uint64_t ts;
- ssize_t written;
-
- ts = (tv->tv_sec - 946684800ll) * 1000000ll + tv->tv_usec;
-
- pkt.size = htobe32(size);
- pkt.len = htobe32(size);
- pkt.flags = htobe32(flags);
- pkt.drops = htobe32(0);
- pkt.ts = htobe64(ts + 0x00E03AB44A676000ll);
-
-#ifdef __TIZEN_PATCH__
- if ((btsnoop_rotate > 0 && btsnoop_size > 0) &&
- lseek(btsnoop_fd, 0x00, SEEK_CUR) +
- BTSNOOP_PKT_SIZE + size > btsnoop_size) {
- btsnoop_rotate_files();
- btsnoop_create_2();
- if (btsnoop_fd < 0)
- return;
- }
-#endif
-
- written = write(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
- if (written < 0)
- return;
-
- if (data && size > 0) {
- written = write(btsnoop_fd, data, size);
- if (written < 0)
- return;
- }
-}
-
-static uint32_t get_flags_from_opcode(uint16_t opcode)
-{
- switch (opcode) {
- case BTSNOOP_OPCODE_NEW_INDEX:
- case BTSNOOP_OPCODE_DEL_INDEX:
- break;
- case BTSNOOP_OPCODE_COMMAND_PKT:
- return 0x02;
- case BTSNOOP_OPCODE_EVENT_PKT:
- return 0x03;
- case BTSNOOP_OPCODE_ACL_TX_PKT:
- return 0x00;
- case BTSNOOP_OPCODE_ACL_RX_PKT:
- return 0x01;
- case BTSNOOP_OPCODE_SCO_TX_PKT:
- case BTSNOOP_OPCODE_SCO_RX_PKT:
- break;
- }
-
- return 0xff;
-}
-
-void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
- const void *data, uint16_t size)
-{
- uint32_t flags;
-
- if (!tv)
- return;
-
- if (btsnoop_fd < 0)
- return;
-
- switch (btsnoop_type) {
- case BTSNOOP_TYPE_HCI:
- if (btsnoop_index == 0xffff)
- btsnoop_index = index;
-
- if (index != btsnoop_index)
- return;
-
- flags = get_flags_from_opcode(opcode);
- if (flags == 0xff)
- return;
- break;
-
- case BTSNOOP_TYPE_MONITOR:
- flags = (index << 16) | opcode;
- break;
-
- default:
- return;
- }
-
- btsnoop_write(tv, flags, data, size);
-}
-
-void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
- const void *data, uint16_t size)
-{
- uint32_t flags;
-
- if (!tv)
- return;
-
- if (btsnoop_fd < 0)
- return;
-
- switch (btsnoop_type) {
- case BTSNOOP_TYPE_SIMULATOR:
- flags = (1 << 16) | frequency;
- break;
-
- default:
- return;
- }
-
- btsnoop_write(tv, flags, data, size);
-}
-
-int btsnoop_open(const char *path, uint32_t *type)
-{
- struct btsnoop_hdr hdr;
- ssize_t len;
-
- if (btsnoop_fd >= 0) {
- fprintf(stderr, "Too many open files\n");
- return -1;
- }
-
- btsnoop_fd = open(path, O_RDONLY | O_CLOEXEC);
- if (btsnoop_fd < 0) {
- perror("Failed to open file");
- return -1;
- }
-
- len = read(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
- if (len < 0 || len != BTSNOOP_HDR_SIZE) {
- perror("Failed to read header");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- if (memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
- fprintf(stderr, "Invalid btsnoop header\n");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- if (be32toh(hdr.version) != btsnoop_version) {
- fprintf(stderr, "Invalid btsnoop version\n");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- btsnoop_type = be32toh(hdr.type);
-
- if (type)
- *type = btsnoop_type;
-
- return 0;
-}
-
-static uint16_t get_opcode_from_flags(uint8_t type, uint32_t flags)
-{
- switch (type) {
- case HCI_COMMAND_PKT:
- return BTSNOOP_OPCODE_COMMAND_PKT;
- case HCI_ACLDATA_PKT:
- if (flags & 0x01)
- return BTSNOOP_OPCODE_ACL_RX_PKT;
- else
- return BTSNOOP_OPCODE_ACL_TX_PKT;
- case HCI_SCODATA_PKT:
- if (flags & 0x01)
- return BTSNOOP_OPCODE_SCO_RX_PKT;
- else
- return BTSNOOP_OPCODE_SCO_TX_PKT;
- case HCI_EVENT_PKT:
- return BTSNOOP_OPCODE_EVENT_PKT;
- case 0xff:
- if (flags & 0x02) {
- if (flags & 0x01)
- return BTSNOOP_OPCODE_EVENT_PKT;
- else
- return BTSNOOP_OPCODE_COMMAND_PKT;
- } else {
- if (flags & 0x01)
- return BTSNOOP_OPCODE_ACL_RX_PKT;
- else
- return BTSNOOP_OPCODE_ACL_TX_PKT;
- }
- break;
- }
-
- return 0xff;
-}
-
-int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
- void *data, uint16_t *size)
-{
- struct btsnoop_pkt pkt;
- uint32_t toread, flags;
- uint64_t ts;
- uint8_t pkt_type;
- ssize_t len;
-
- if (btsnoop_fd < 0)
- return -1;
-
- len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
- if (len == 0)
- return -1;
-
- if (len < 0 || len != BTSNOOP_PKT_SIZE) {
- perror("Failed to read packet");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- toread = be32toh(pkt.size);
- if (toread > BTSNOOP_MAX_PACKET_SIZE) {
- perror("Packet len suspicially big: %u", toread);
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- flags = be32toh(pkt.flags);
-
- ts = be64toh(pkt.ts) - 0x00E03AB44A676000ll;
- tv->tv_sec = (ts / 1000000ll) + 946684800ll;
- tv->tv_usec = ts % 1000000ll;
-
- switch (btsnoop_type) {
- case BTSNOOP_TYPE_HCI:
- *index = 0;
- *opcode = get_opcode_from_flags(0xff, flags);
- break;
-
- case BTSNOOP_TYPE_UART:
- len = read(btsnoop_fd, &pkt_type, 1);
- if (len < 0) {
- perror("Failed to read packet type");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
- toread--;
-
- *index = 0;
- *opcode = get_opcode_from_flags(pkt_type, flags);
- break;
-
- case BTSNOOP_TYPE_MONITOR:
- *index = flags >> 16;
- *opcode = flags & 0xffff;
- break;
-
- default:
- fprintf(stderr, "Unknown packet type\n");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- len = read(btsnoop_fd, data, toread);
- if (len < 0) {
- perror("Failed to read data");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- *size = toread;
-
- return 0;
-}
-
-int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
- void *data, uint16_t *size)
-{
- struct btsnoop_pkt pkt;
- uint32_t toread, flags;
- uint64_t ts;
- ssize_t len;
-
- if (btsnoop_fd < 0)
- return -1;
-
- len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
- if (len == 0)
- return -1;
-
- if (len < 0 || len != BTSNOOP_PKT_SIZE) {
- perror("Failed to read packet");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- toread = be32toh(pkt.size);
- flags = be32toh(pkt.flags);
-
- ts = be64toh(pkt.ts) - 0x00E03AB44A676000ll;
- tv->tv_sec = (ts / 1000000ll) + 946684800ll;
- tv->tv_usec = ts % 1000000ll;
-
- switch (btsnoop_type) {
- case BTSNOOP_TYPE_SIMULATOR:
- if ((flags >> 16) != 1)
- break;
- *frequency = flags & 0xffff;
- break;
-
- default:
- fprintf(stderr, "Unknown packet type\n");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- len = read(btsnoop_fd, data, toread);
- if (len < 0) {
- perror("Failed to read data");
- close(btsnoop_fd);
- btsnoop_fd = -1;
- return -1;
- }
-
- *size = toread;
-
- return 0;
-}
-
-void btsnoop_close(void)
-{
- if (btsnoop_fd < 0)
- return;
-
-#ifdef __TIZEN_PATCH__
- if (btsnoop_path) {
- free(btsnoop_path);
- btsnoop_path = NULL;
- }
- btsnoop_rotate = -1;
- btsnoop_size = -1;
-#endif
-
- close(btsnoop_fd);
- btsnoop_fd = -1;
-
- btsnoop_index = 0xffff;
-}
diff --git a/monitor/btsnoop.h b/monitor/btsnoop.h
deleted file mode 100644
index 10f76f20..00000000
--- a/monitor/btsnoop.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2014 Intel Corporation
- * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <stdint.h>
-#include <sys/time.h>
-
-#define BTSNOOP_TYPE_HCI 1001
-#define BTSNOOP_TYPE_UART 1002
-#define BTSNOOP_TYPE_BCSP 1003
-#define BTSNOOP_TYPE_3WIRE 1004
-#define BTSNOOP_TYPE_MONITOR 2001
-#define BTSNOOP_TYPE_SIMULATOR 2002
-
-#define BTSNOOP_OPCODE_NEW_INDEX 0
-#define BTSNOOP_OPCODE_DEL_INDEX 1
-#define BTSNOOP_OPCODE_COMMAND_PKT 2
-#define BTSNOOP_OPCODE_EVENT_PKT 3
-#define BTSNOOP_OPCODE_ACL_TX_PKT 4
-#define BTSNOOP_OPCODE_ACL_RX_PKT 5
-#define BTSNOOP_OPCODE_SCO_TX_PKT 6
-#define BTSNOOP_OPCODE_SCO_RX_PKT 7
-
-struct btsnoop_opcode_new_index {
- uint8_t type;
- uint8_t bus;
- uint8_t bdaddr[6];
- char name[8];
-} __attribute__((packed));
-
-#ifdef __TIZEN_PATCH__
-void btsnoop_create(const char *path, uint32_t type,
- int16_t rotate_count, ssize_t file_size);
-#else
-void btsnoop_create(const char *path, uint32_t type);
-#endif
-void btsnoop_write(struct timeval *tv, uint32_t flags,
- const void *data, uint16_t size);
-void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
- const void *data, uint16_t size);
-void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
- const void *data, uint16_t size);
-int btsnoop_open(const char *path, uint32_t *type);
-int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
- void *data, uint16_t *size);
-int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
- void *data, uint16_t *size);
-void btsnoop_close(void);
diff --git a/monitor/control.c b/monitor/control.c
index e88a6e34..0d58ecd8 100644
--- a/monitor/control.c
+++ b/monitor/control.c
@@ -261,16 +261,34 @@ static void mgmt_local_name_changed(uint16_t len, const void *buf)
static void mgmt_new_link_key(uint16_t len, const void *buf)
{
const struct mgmt_ev_new_link_key *ev = buf;
+ const char *type;
char str[18];
+ static const char *types[] = {
+ "Combination key",
+ "Local Unit key",
+ "Remote Unit key",
+ "Debug Combination key",
+ "Unauthenticated Combination key from P-192",
+ "Authenticated Combination key from P-192",
+ "Changed Combination key",
+ "Unauthenticated Combination key from P-256",
+ "Authenticated Combination key from P-256",
+ };
if (len < sizeof(*ev)) {
printf("* Malformed New Link Key control\n");
return;
}
+ if (ev->key.type < NELEM(types))
+ type = types[ev->key.type];
+ else
+ type = "Reserved";
+
ba2str(&ev->key.addr.bdaddr, str);
- printf("@ New Link Key: %s (%d)\n", str, ev->key.addr.type);
+ printf("@ New Link Key: %s (%d) %s (%u)\n", str,
+ ev->key.addr.type, type, ev->key.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -884,7 +902,7 @@ void control_message(uint16_t opcode, const void *data, uint16_t size)
static void data_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data = user_data;
- unsigned char control[32];
+ unsigned char control[64];
struct mgmt_hdr hdr;
struct msghdr msg;
struct iovec iov[2];
@@ -909,6 +927,8 @@ static void data_callback(int fd, uint32_t events, void *user_data)
struct cmsghdr *cmsg;
struct timeval *tv = NULL;
struct timeval ctv;
+ struct ucred *cred = NULL;
+ struct ucred ccred;
uint16_t opcode, index, pktlen;
ssize_t len;
@@ -928,6 +948,11 @@ static void data_callback(int fd, uint32_t events, void *user_data)
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
}
+
+ if (cmsg->cmsg_type == SCM_CREDENTIALS) {
+ memcpy(&ccred, CMSG_DATA(cmsg), sizeof(ccred));
+ cred = &ccred;
+ }
}
opcode = le16_to_cpu(hdr.opcode);
@@ -936,14 +961,16 @@ static void data_callback(int fd, uint32_t events, void *user_data)
switch (data->channel) {
case HCI_CHANNEL_CONTROL:
- packet_control(tv, index, opcode, data->buf, pktlen);
+ packet_control(tv, cred, index, opcode,
+ data->buf, pktlen);
break;
case HCI_CHANNEL_MONITOR:
btsnoop_write_hci(btsnoop_file, tv, index, opcode,
data->buf, pktlen);
ellisys_inject_hci(tv, index, opcode,
data->buf, pktlen);
- packet_monitor(tv, index, opcode, data->buf, pktlen);
+ packet_monitor(tv, cred, index, opcode,
+ data->buf, pktlen);
break;
}
}
@@ -983,6 +1010,12 @@ static int open_socket(uint16_t channel)
return -1;
}
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)) < 0) {
+ perror("Failed to enable credentials");
+ close(fd);
+ return -1;
+ }
+
return fd;
}
@@ -1033,7 +1066,7 @@ static void client_callback(int fd, uint32_t events, void *user_data)
uint16_t opcode = le16_to_cpu(hdr->opcode);
uint16_t index = le16_to_cpu(hdr->index);
- packet_monitor(NULL, index, opcode,
+ packet_monitor(NULL, NULL, index, opcode,
data->buf + MGMT_HDR_SIZE, pktlen);
data->offset -= pktlen + MGMT_HDR_SIZE;
@@ -1131,10 +1164,10 @@ bool control_writer(const char *path)
#endif
{
#ifdef __TIZEN_PATCH__
- btsnoop_file = btsnoop_create(path, BTSNOOP_TYPE_MONITOR,
+ btsnoop_file = btsnoop_create(path, BTSNOOP_FORMAT_MONITOR,
rotate_count, file_size);
#else
- btsnoop_file = btsnoop_create(path, BTSNOOP_TYPE_MONITOR);
+ btsnoop_file = btsnoop_create(path, BTSNOOP_FORMAT_MONITOR);
#endif
return !!btsnoop_file;
@@ -1144,33 +1177,36 @@ void control_reader(const char *path)
{
unsigned char buf[BTSNOOP_MAX_PACKET_SIZE];
uint16_t pktlen;
- uint32_t type;
+ uint32_t format;
struct timeval tv;
btsnoop_file = btsnoop_open(path, BTSNOOP_FLAG_PKLG_SUPPORT);
if (!btsnoop_file)
return;
- type = btsnoop_get_type(btsnoop_file);
+ format = btsnoop_get_format(btsnoop_file);
- switch (type) {
- case BTSNOOP_TYPE_HCI:
- case BTSNOOP_TYPE_UART:
- case BTSNOOP_TYPE_SIMULATOR:
+ switch (format) {
+ case BTSNOOP_FORMAT_HCI:
+ case BTSNOOP_FORMAT_UART:
+ case BTSNOOP_FORMAT_SIMULATOR:
packet_del_filter(PACKET_FILTER_SHOW_INDEX);
break;
- case BTSNOOP_TYPE_MONITOR:
+ case BTSNOOP_FORMAT_MONITOR:
packet_add_filter(PACKET_FILTER_SHOW_INDEX);
break;
}
+#ifdef __TIZEN_PATCH__
+ setenv("PAGER", "cat", 0);
+#endif
open_pager();
- switch (type) {
- case BTSNOOP_TYPE_HCI:
- case BTSNOOP_TYPE_UART:
- case BTSNOOP_TYPE_MONITOR:
+ switch (format) {
+ case BTSNOOP_FORMAT_HCI:
+ case BTSNOOP_FORMAT_UART:
+ case BTSNOOP_FORMAT_MONITOR:
while (1) {
uint16_t index, opcode;
@@ -1181,12 +1217,12 @@ void control_reader(const char *path)
if (opcode == 0xffff)
continue;
- packet_monitor(&tv, index, opcode, buf, pktlen);
+ packet_monitor(&tv, NULL, index, opcode, buf, pktlen);
ellisys_inject_hci(&tv, index, opcode, buf, pktlen);
}
break;
- case BTSNOOP_TYPE_SIMULATOR:
+ case BTSNOOP_FORMAT_SIMULATOR:
while (1) {
uint16_t frequency;
diff --git a/monitor/display.h b/monitor/display.h
index e6274019..36e189a3 100644
--- a/monitor/display.h
+++ b/monitor/display.h
@@ -35,10 +35,13 @@ bool use_color(void);
#define COLOR_MAGENTA "\x1B[0;35m"
#define COLOR_CYAN "\x1B[0;36m"
#define COLOR_WHITE "\x1B[0;37m"
-#define COLOR_WHITE_BG "\x1B[0;47m"
+#define COLOR_WHITE_BG "\x1B[0;47;30m"
#define COLOR_HIGHLIGHT "\x1B[1;39m"
#define COLOR_ERROR "\x1B[1;31m"
+#define COLOR_WARN "\x1B[1m"
+#define COLOR_INFO COLOR_OFF
+#define COLOR_DEBUG COLOR_WHITE
#define FALLBACK_TERMINAL_WIDTH 80
diff --git a/monitor/hcidump.c b/monitor/hcidump.c
index e910c5ec..bef1338f 100644
--- a/monitor/hcidump.c
+++ b/monitor/hcidump.c
@@ -160,17 +160,19 @@ static void device_callback(int fd, uint32_t events, void *user_data)
switch (buf[0]) {
case HCI_COMMAND_PKT:
- packet_hci_command(tv, data->index, buf + 1, len - 1);
+ packet_hci_command(tv, NULL, data->index,
+ buf + 1, len - 1);
break;
case HCI_EVENT_PKT:
- packet_hci_event(tv, data->index, buf + 1, len - 1);
+ packet_hci_event(tv, NULL, data->index,
+ buf + 1, len - 1);
break;
case HCI_ACLDATA_PKT:
- packet_hci_acldata(tv, data->index, !!dir,
+ packet_hci_acldata(tv, NULL, data->index, !!dir,
buf + 1, len - 1);
break;
case HCI_SCODATA_PKT:
- packet_hci_scodata(tv, data->index, !!dir,
+ packet_hci_scodata(tv, NULL, data->index, !!dir,
buf + 1, len - 1);
break;
}
diff --git a/monitor/intel.c b/monitor/intel.c
new file mode 100644
index 00000000..1ca9a95e
--- /dev/null
+++ b/monitor/intel.c
@@ -0,0 +1,932 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+
+#include "src/shared/util.h"
+#include "display.h"
+#include "packet.h"
+#include "lmp.h"
+#include "ll.h"
+#include "vendor.h"
+#include "intel.h"
+
+#define COLOR_UNKNOWN_EVENT_MASK COLOR_WHITE_BG
+#define COLOR_UNKNOWN_SCAN_STATUS COLOR_WHITE_BG
+
+static void print_status(uint8_t status)
+{
+ packet_print_error("Status", status);
+}
+
+static void print_module(uint8_t module)
+{
+ const char *str;
+
+ switch (module) {
+ case 0x01:
+ str = "BC";
+ break;
+ case 0x02:
+ str = "HCI";
+ break;
+ case 0x03:
+ str = "LLC";
+ break;
+ case 0x04:
+ str = "OS";
+ break;
+ case 0x05:
+ str = "LM";
+ break;
+ case 0x06:
+ str = "SC";
+ break;
+ case 0x07:
+ str = "SP";
+ break;
+ case 0x08:
+ str = "OSAL";
+ break;
+ case 0x09:
+ str = "LC";
+ break;
+ case 0x0a:
+ str = "APP";
+ break;
+ case 0x0b:
+ str = "TLD";
+ break;
+ case 0xf0:
+ str = "Debug";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Module: %s (0x%2.2x)", str, module);
+}
+
+static void null_cmd(const void *data, uint8_t size)
+{
+}
+
+static void status_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+
+ print_status(status);
+}
+
+static void reset_cmd(const void *data, uint8_t size)
+{
+ uint8_t reset_type = get_u8(data);
+ uint8_t patch_enable = get_u8(data + 1);
+ uint8_t ddc_reload = get_u8(data + 2);
+ uint8_t boot_option = get_u8(data + 3);
+ uint32_t boot_addr = get_le32(data + 4);
+ const char *str;
+
+ switch (reset_type) {
+ case 0x00:
+ str = "Soft software reset";
+ break;
+ case 0x01:
+ str = "Hard software reset";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Reset type: %s (0x%2.2x)", str, reset_type);
+
+ switch (patch_enable) {
+ case 0x00:
+ str = "Do not enable";
+ break;
+ case 0x01:
+ str = "Enable";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Patch vectors: %s (0x%2.2x)", str, patch_enable);
+
+ switch (ddc_reload) {
+ case 0x00:
+ str = "Do not reload";
+ break;
+ case 0x01:
+ str = "Reload from OTP";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("DDC parameters: %s (0x%2.2x)", str, ddc_reload);
+
+ switch (boot_option) {
+ case 0x00:
+ str = "Current image";
+ break;
+ case 0x01:
+ str = "Specified address";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Boot option: %s (0x%2.2x)", str, boot_option);
+ print_field("Boot address: 0x%8.8x", boot_addr);
+}
+
+static void read_version_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+ uint8_t hw_platform = get_u8(data + 1);
+ uint8_t hw_variant = get_u8(data + 2);
+ uint8_t hw_revision = get_u8(data + 3);
+ uint8_t fw_variant = get_u8(data + 4);
+ uint8_t fw_revision = get_u8(data + 5);
+ uint8_t fw_build_nn = get_u8(data + 6);
+ uint8_t fw_build_cw = get_u8(data + 7);
+ uint8_t fw_build_yy = get_u8(data + 8);
+ uint8_t fw_patch = get_u8(data + 9);
+
+ print_status(status);
+ print_field("Hardware platform: 0x%2.2x", hw_platform);
+ print_field("Hardware variant: 0x%2.2x", hw_variant);
+ print_field("Hardware revision: %u.%u", hw_revision >> 4,
+ hw_revision & 0x0f);
+ print_field("Firmware variant: 0x%2.2x", fw_variant);
+ print_field("Firmware revision: %u.%u", fw_revision >> 4,
+ fw_revision & 0x0f);
+
+ print_field("Firmware build: %u-%u.%u", fw_build_nn,
+ fw_build_cw, 2000 + fw_build_yy);
+ print_field("Firmware patch: %u", fw_patch);
+}
+
+static void secure_send_cmd(const void *data, uint8_t size)
+{
+ uint8_t type = get_u8(data);
+ const char *str;
+
+ switch (type) {
+ case 0x00:
+ str = "Init";
+ break;
+ case 0x01:
+ str = "Data";
+ break;
+ case 0x02:
+ str = "Sign";
+ break;
+ case 0x03:
+ str = "PKey";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Type: %s fragment (0x%2.2x)", str, type);
+
+ packet_hexdump(data + 1, size - 1);
+}
+
+static void manufacturer_mode_cmd(const void *data, uint8_t size)
+{
+ uint8_t mode = get_u8(data);
+ uint8_t reset = get_u8(data + 1);
+ const char *str;
+
+ switch (mode) {
+ case 0x00:
+ str = "Disabled";
+ break;
+ case 0x01:
+ str = "Enabled";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Mode switch: %s (0x%2.2x)", str, mode);
+
+ switch (reset) {
+ case 0x00:
+ str = "No reset";
+ break;
+ case 0x01:
+ str = "Reset and deactivate patches";
+ break;
+ case 0x02:
+ str = "Reset and activate patches";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Reset behavior: %s (0x%2.2x)", str, reset);
+}
+
+static void write_bd_data_cmd(const void *data, uint8_t size)
+{
+ uint8_t features[8];
+
+ packet_print_addr("Address", data, false);
+ packet_hexdump(data + 6, 6);
+
+ memcpy(features, data + 12, 8);
+ packet_print_features_lmp(features, 0);
+
+ memcpy(features, data + 20, 1);
+ memset(features + 1, 0, 7);
+ packet_print_features_ll(features);
+
+ packet_hexdump(data + 21, size - 21);
+}
+
+static void read_bd_data_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+
+ print_status(status);
+ packet_print_addr("Address", data + 1, false);
+ packet_hexdump(data + 7, size - 7);
+}
+
+static void write_bd_address_cmd(const void *data, uint8_t size)
+{
+ packet_print_addr("Address", data, false);
+}
+
+static void act_deact_traces_cmd(const void *data, uint8_t size)
+{
+ uint8_t tx = get_u8(data);
+ uint8_t tx_arq = get_u8(data + 1);
+ uint8_t rx = get_u8(data + 2);
+
+ print_field("Transmit traces: 0x%2.2x", tx);
+ print_field("Transmit ARQ: 0x%2.2x", tx_arq);
+ print_field("Receive traces: 0x%2.2x", rx);
+}
+
+static void stimulate_exception_cmd(const void *data, uint8_t size)
+{
+ uint8_t type = get_u8(data);
+ const char *str;
+
+ switch (type) {
+ case 0x00:
+ str = "Fatal Exception";
+ break;
+ case 0x01:
+ str = "Debug Exception";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Type: %s (0x%2.2x)", str, type);
+}
+
+static const struct {
+ uint8_t bit;
+ const char *str;
+} events_table[] = {
+ { 0, "Bootup" },
+ { 1, "SCO Rejected via LMP" },
+ { 2, "PTT Switch Notification" },
+ { 7, "Scan Status" },
+ { 9, "Debug Exception" },
+ { 10, "Fatal Exception" },
+ { 11, "System Exception" },
+ { 13, "LE Link Established" },
+ { 14, "FW Trace String" },
+ { }
+};
+
+static void set_event_mask_cmd(const void *data, uint8_t size)
+{
+ const uint8_t *events_array = data;
+ uint64_t mask, events = 0;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ events |= ((uint64_t) events_array[i]) << (i * 8);
+
+ print_field("Mask: 0x%16.16" PRIx64, events);
+
+ mask = events;
+
+ for (i = 0; events_table[i].str; i++) {
+ if (events & (((uint64_t) 1) << events_table[i].bit)) {
+ print_field(" %s", events_table[i].str);
+ mask &= ~(((uint64_t) 1) << events_table[i].bit);
+ }
+ }
+
+ if (mask)
+ print_text(COLOR_UNKNOWN_EVENT_MASK, " Unknown mask "
+ "(0x%16.16" PRIx64 ")", mask);
+}
+
+static void ddc_config_write_cmd(const void *data, uint8_t size)
+{
+ while (size > 0) {
+ uint8_t param_len = get_u8(data);
+ uint16_t param_id = get_le16(data + 1);
+
+ print_field("Identifier: 0x%4.4x", param_id);
+ packet_hexdump(data + 2, param_len - 2);
+
+ data += param_len + 1;
+ size -= param_len + 1;
+ }
+}
+
+static void ddc_config_write_rsp(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+ uint16_t param_id = get_le16(data + 1);
+
+ print_status(status);
+ print_field("Identifier: 0x%4.4x", param_id);
+}
+
+static void memory_write_cmd(const void *data, uint8_t size)
+{
+ uint32_t addr = get_le32(data);
+ uint8_t mode = get_u8(data + 4);
+ uint8_t length = get_u8(data + 5);
+ const char *str;
+
+ print_field("Address: 0x%8.8x", addr);
+
+ switch (mode) {
+ case 0x00:
+ str = "Byte access";
+ break;
+ case 0x01:
+ str = "Half word access";
+ break;
+ case 0x02:
+ str = "Word access";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Mode: %s (0x%2.2x)", str, mode);
+ print_field("Length: %u", length);
+
+ packet_hexdump(data + 6, size - 6);
+}
+
+static const struct vendor_ocf vendor_ocf_table[] = {
+ { 0x001, "Reset",
+ reset_cmd, 8, true,
+ status_rsp, 1, true },
+ { 0x002, "No Operation" },
+ { 0x005, "Read Version",
+ null_cmd, 0, true,
+ read_version_rsp, 10, true },
+ { 0x006, "Set UART Baudrate" },
+ { 0x007, "Enable LPM" },
+ { 0x008, "PCM Write Configuration" },
+ { 0x009, "Secure Send",
+ secure_send_cmd, 1, false,
+ status_rsp, 1, true },
+ { 0x00d, "Read Secure Boot Params",
+ null_cmd, 0, true },
+ { 0x00e, "Write Secure Boot Params" },
+ { 0x00f, "Unlock" },
+ { 0x010, "Change UART Baudrate" },
+ { 0x011, "Manufacturer Mode",
+ manufacturer_mode_cmd, 2, true,
+ status_rsp, 1, true },
+ { 0x012, "Read Link RSSI" },
+ { 0x022, "Get Exception Info" },
+ { 0x024, "Clear Exception Info" },
+ { 0x02f, "Write BD Data",
+ write_bd_data_cmd, 6, false },
+ { 0x030, "Read BD Data",
+ null_cmd, 0, true,
+ read_bd_data_rsp, 7, false },
+ { 0x031, "Write BD Address",
+ write_bd_address_cmd, 6, true,
+ status_rsp, 1, true },
+ { 0x032, "Flow Specification" },
+ { 0x034, "Read Secure ID" },
+ { 0x038, "Set Synchronous USB Interface Type" },
+ { 0x039, "Config Synchronous Interface" },
+ { 0x03f, "SW RF Kill",
+ null_cmd, 0, true,
+ status_rsp, 1, true },
+ { 0x043, "Activate Deactivate Traces",
+ act_deact_traces_cmd, 3, true },
+ { 0x04d, "Stimulate Exception",
+ stimulate_exception_cmd, 1, true,
+ status_rsp, 1, true },
+ { 0x050, "Read HW Version" },
+ { 0x052, "Set Event Mask",
+ set_event_mask_cmd, 8, true,
+ status_rsp, 1, true },
+ { 0x053, "Config_Link_Controller" },
+ { 0x089, "DDC Write" },
+ { 0x08a, "DDC Read" },
+ { 0x08b, "DDC Config Write",
+ ddc_config_write_cmd, 3, false,
+ ddc_config_write_rsp, 3, true },
+ { 0x08c, "DDC Config Read" },
+ { 0x08d, "Memory Read" },
+ { 0x08e, "Memory Write",
+ memory_write_cmd, 6, false,
+ status_rsp, 1, true },
+ { }
+};
+
+const struct vendor_ocf *intel_vendor_ocf(uint16_t ocf)
+{
+ int i;
+
+ for (i = 0; vendor_ocf_table[i].str; i++) {
+ if (vendor_ocf_table[i].ocf == ocf)
+ return &vendor_ocf_table[i];
+ }
+
+ return NULL;
+}
+
+static void startup_evt(const void *data, uint8_t size)
+{
+}
+
+static void fatal_exception_evt(const void *data, uint8_t size)
+{
+ uint16_t line = get_le16(data);
+ uint8_t module = get_u8(data + 2);
+ uint8_t reason = get_u8(data + 3);
+
+ print_field("Line: %u", line);
+ print_module(module);
+ print_field("Reason: 0x%2.2x", reason);
+}
+
+static void bootup_evt(const void *data, uint8_t size)
+{
+ uint8_t zero = get_u8(data);
+ uint8_t num_packets = get_u8(data + 1);
+ uint8_t source = get_u8(data + 2);
+ uint8_t reset_type = get_u8(data + 3);
+ uint8_t reset_reason = get_u8(data + 4);
+ uint8_t ddc_status = get_u8(data + 5);
+ const char *str;
+
+ print_field("Zero: 0x%2.2x", zero);
+ print_field("Number of packets: %d", num_packets);
+
+ switch (source) {
+ case 0x00:
+ str = "Bootloader";
+ break;
+ case 0x01:
+ str = "Operational firmware";
+ break;
+ case 0x02:
+ str = "Self test firmware";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Source: %s (0x%2.2x)", str, source);
+
+ switch (reset_type) {
+ case 0x00:
+ str = "Hardware reset";
+ break;
+ case 0x01:
+ str = "Soft watchdog reset";
+ break;
+ case 0x02:
+ str = "Soft software reset";
+ break;
+ case 0x03:
+ str = "Hard watchdog reset";
+ break;
+ case 0x04:
+ str = "Hard software reset";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Reset type: %s (0x%2.2x)", str, reset_type);
+
+ switch (reset_reason) {
+ case 0x00:
+ str = "Power on";
+ break;
+ case 0x01:
+ str = "Reset command";
+ break;
+ case 0x02:
+ str = "Intel reset command";
+ break;
+ case 0x03:
+ str = "Watchdog";
+ break;
+ case 0x04:
+ str = "Fatal exception";
+ break;
+ case 0x05:
+ str = "System exception";
+ break;
+ case 0xff:
+ str = "Unknown";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Reset reason: %s (0x%2.2x)", str, reset_reason);
+
+ switch (ddc_status) {
+ case 0x00:
+ str = "Firmware default";
+ break;
+ case 0x01:
+ str = "Firmware default plus OTP";
+ break;
+ case 0x02:
+ str = "Persistent RAM";
+ break;
+ case 0x03:
+ str = "Not used";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("DDC status: %s (0x%2.2x)", str, ddc_status);
+}
+
+static void default_bd_data_evt(const void *data, uint8_t size)
+{
+ uint8_t mem_status = get_u8(data);
+ const char *str;
+
+ switch (mem_status) {
+ case 0x02:
+ str = "Invalid manufacturing data";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Memory status: %s (0x%2.2x)", str, mem_status);
+}
+
+static void secure_send_commands_result_evt(const void *data, uint8_t size)
+{
+ uint8_t result = get_u8(data);
+ uint16_t opcode = get_le16(data + 1);
+ uint16_t ogf = cmd_opcode_ogf(opcode);
+ uint16_t ocf = cmd_opcode_ocf(opcode);
+ uint8_t status = get_u8(data + 3);
+ const char *str;
+
+ switch (result) {
+ case 0x00:
+ str = "Success";
+ break;
+ case 0x01:
+ str = "General failure";
+ break;
+ case 0x02:
+ str = "Hardware failure";
+ break;
+ case 0x03:
+ str = "Signature verification failed";
+ break;
+ case 0x04:
+ str = "Parsing error of command buffer";
+ break;
+ case 0x05:
+ str = "Command execution failure";
+ break;
+ case 0x06:
+ str = "Command parameters error";
+ break;
+ case 0x07:
+ str = "Command missing";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Result: %s (0x%2.2x)", str, result);
+ print_field("Opcode: 0x%4.4x (0x%2.2x|0x%4.4x)", opcode, ogf, ocf);
+ print_status(status);
+}
+
+static void debug_exception_evt(const void *data, uint8_t size)
+{
+ uint16_t line = get_le16(data);
+ uint8_t module = get_u8(data + 2);
+ uint8_t reason = get_u8(data + 3);
+
+ print_field("Line: %u", line);
+ print_module(module);
+ print_field("Reason: 0x%2.2x", reason);
+}
+
+static void le_link_established_evt(const void *data, uint8_t size)
+{
+ uint16_t handle = get_le16(data);
+ uint32_t access_addr = get_le32(data + 10);
+
+ print_field("Handle: %u", handle);
+
+ packet_hexdump(data + 2, 8);
+
+ print_field("Access address: 0x%8.8x", access_addr);
+
+ packet_hexdump(data + 14, size - 14);
+}
+
+static void scan_status_evt(const void *data, uint8_t size)
+{
+ uint8_t enable = get_u8(data);
+
+ print_field("Inquiry scan: %s",
+ (enable & 0x01) ? "Enabled" : "Disabled");
+ print_field("Page scan: %s",
+ (enable & 0x02) ? "Enabled" : "Disabled");
+
+ if (enable & 0xfc)
+ print_text(COLOR_UNKNOWN_SCAN_STATUS,
+ " Unknown status (0x%2.2x)", enable & 0xfc);
+
+}
+
+static void act_deact_traces_complete_evt(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+
+ print_status(status);
+}
+
+static void lmp_pdu_trace_evt(const void *data, uint8_t size)
+{
+ uint8_t type, len, id;
+ uint16_t handle, count;
+ uint32_t clock;
+ const char *str;
+
+ type = get_u8(data);
+ handle = get_le16(data + 1);
+
+ switch (type) {
+ case 0x00:
+ str = "RX LMP";
+ break;
+ case 0x01:
+ str = "TX LMP";
+ break;
+ case 0x02:
+ str = "ACK LMP";
+ break;
+ case 0x03:
+ str = "RX LL";
+ break;
+ case 0x04:
+ str = "TX LL";
+ break;
+ case 0x05:
+ str = "ACK LL";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ print_field("Type: %s (0x%2.2x)", str, type);
+ print_field("Handle: %u", handle);
+
+ switch (type) {
+ case 0x00:
+ len = size - 8;
+ clock = get_le32(data + 4 + len);
+
+ packet_hexdump(data + 3, 1);
+ lmp_packet(data + 4, len, false);
+ print_field("Clock: 0x%8.8x", clock);
+ break;
+ case 0x01:
+ len = size - 9;
+ clock = get_le32(data + 4 + len);
+ id = get_u8(data + 4 + len + 4);
+
+ packet_hexdump(data + 3, 1);
+ lmp_packet(data + 4, len, false);
+ print_field("Clock: 0x%8.8x", clock);
+ print_field("ID: 0x%2.2x", id);
+ break;
+ case 0x02:
+ clock = get_le32(data + 3);
+ id = get_u8(data + 3 + 4);
+
+ print_field("Clock: 0x%8.8x", clock);
+ print_field("ID: 0x%2.2x", id);
+ break;
+ case 0x03:
+ len = size - 8;
+ count = get_le16(data + 3);
+
+ print_field("Count: 0x%4.4x", count);
+ packet_hexdump(data + 3 + 2 + 1, 2);
+ llcp_packet(data + 8, len, false);
+ break;
+ case 0x04:
+ len = size - 8;
+ count = get_le16(data + 3);
+ id = get_u8(data + 3 + 2);
+
+ print_field("Count: 0x%4.4x", count);
+ print_field("ID: 0x%2.2x", id);
+ packet_hexdump(data + 3 + 2 + 1, 2);
+ llcp_packet(data + 8, len, false);
+ break;
+ case 0x05:
+ count = get_le16(data + 3);
+ id = get_u8(data + 3 + 2);
+
+ print_field("Count: 0x%4.4x", count);
+ print_field("ID: 0x%2.2x", id);
+ break;
+ default:
+ packet_hexdump(data + 3, size - 3);
+ break;
+ }
+}
+
+static void write_bd_data_complete_evt(const void *data, uint8_t size)
+{
+ uint8_t status = get_u8(data);
+
+ print_status(status);
+}
+
+static void sco_rejected_via_lmp_evt(const void *data, uint8_t size)
+{
+ uint8_t reason = get_u8(data + 6);
+
+ packet_print_addr("Address", data, false);
+ packet_print_error("Reason", reason);
+}
+
+static void ptt_switch_notification_evt(const void *data, uint8_t size)
+{
+ uint16_t handle = get_le16(data);
+ uint8_t table = get_u8(data + 2);
+ const char *str;
+
+ print_field("Handle: %u", handle);
+
+ switch (table) {
+ case 0x00:
+ str = "Basic rate";
+ break;
+ case 0x01:
+ str = "Enhanced data rate";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Packet type table: %s (0x%2.2x)", str, table);
+}
+
+static void system_exception_evt(const void *data, uint8_t size)
+{
+ uint8_t type = get_u8(data);
+ const char *str;
+
+ switch (type) {
+ case 0x00:
+ str = "No Exception";
+ break;
+ case 0x01:
+ str = "Undefined Instruction";
+ break;
+ case 0x02:
+ str = "Prefetch abort";
+ break;
+ case 0x03:
+ str = "Data abort";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Type: %s (0x%2.2x)", str, type);
+
+ packet_hexdump(data + 1, size - 1);
+}
+
+static const struct vendor_evt vendor_evt_table[] = {
+ { 0x00, "Startup",
+ startup_evt, 0, true },
+ { 0x01, "Fatal Exception",
+ fatal_exception_evt, 4, true },
+ { 0x02, "Bootup",
+ bootup_evt, 6, true },
+ { 0x05, "Default BD Data",
+ default_bd_data_evt, 1, true },
+ { 0x06, "Secure Send Commands Result",
+ secure_send_commands_result_evt, 4, true },
+ { 0x08, "Debug Exception",
+ debug_exception_evt, 4, true },
+ { 0x0f, "LE Link Established",
+ le_link_established_evt, 26, true },
+ { 0x11, "Scan Status",
+ scan_status_evt, 1, true },
+ { 0x16, "Activate Deactivate Traces Complete",
+ act_deact_traces_complete_evt, 1, true },
+ { 0x17, "LMP PDU Trace",
+ lmp_pdu_trace_evt, 3, false },
+ { 0x19, "Write BD Data Complete",
+ write_bd_data_complete_evt, 1, true },
+ { 0x25, "SCO Rejected via LMP",
+ sco_rejected_via_lmp_evt, 7, true },
+ { 0x26, "PTT Switch Notification",
+ ptt_switch_notification_evt, 3, true },
+ { 0x29, "System Exception",
+ system_exception_evt, 133, true },
+ { 0x2c, "FW Trace String" },
+ { 0x2e, "FW Trace Binary" },
+ { }
+};
+
+const struct vendor_evt *intel_vendor_evt(uint8_t evt)
+{
+ int i;
+
+ for (i = 0; vendor_evt_table[i].str; i++) {
+ if (vendor_evt_table[i].evt == evt)
+ return &vendor_evt_table[i];
+ }
+
+ return NULL;
+}
diff --git a/monitor/intel.h b/monitor/intel.h
new file mode 100644
index 00000000..573b23f3
--- /dev/null
+++ b/monitor/intel.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+struct vendor_ocf;
+struct vendor_evt;
+
+const struct vendor_ocf *intel_vendor_ocf(uint16_t ocf);
+const struct vendor_evt *intel_vendor_evt(uint8_t evt);
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 5faa26fd..93a1b20c 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -42,7 +42,9 @@
#include "keys.h"
#include "sdp.h"
#include "avctp.h"
+#include "avdtp.h"
#include "rfcomm.h"
+#include "bnep.h"
/* L2CAP Control Field bit masks */
#define L2CAP_CTRL_SAR_MASK 0xC000
@@ -98,6 +100,7 @@ struct chan_data {
uint8_t ctrlid;
uint8_t mode;
uint8_t ext_ctrl;
+ uint8_t seq_num;
};
static struct chan_data chan_list[MAX_CHAN];
@@ -106,10 +109,13 @@ static void assign_scid(const struct l2cap_frame *frame,
uint16_t scid, uint16_t psm, uint8_t ctrlid)
{
int i, n = -1;
+ uint8_t seq_num = 1;
for (i = 0; i < MAX_CHAN; i++) {
- if (n < 0 && chan_list[i].handle == 0x0000)
+ if (n < 0 && chan_list[i].handle == 0x0000) {
n = i;
+ continue;
+ }
if (chan_list[i].index != frame->index)
continue;
@@ -117,16 +123,18 @@ static void assign_scid(const struct l2cap_frame *frame,
if (chan_list[i].handle != frame->handle)
continue;
+ if (chan_list[i].psm == psm)
+ seq_num++;
+
+ /* Don't break on match - we still need to go through all
+ * channels to find proper seq_num.
+ */
if (frame->in) {
- if (chan_list[i].dcid == scid) {
+ if (chan_list[i].dcid == scid)
n = i;
- break;
- }
} else {
- if (chan_list[i].scid == scid) {
+ if (chan_list[i].scid == scid)
n = i;
- break;
- }
}
}
@@ -146,6 +154,8 @@ static void assign_scid(const struct l2cap_frame *frame,
chan_list[n].psm = psm;
chan_list[n].ctrlid = ctrlid;
chan_list[n].mode = 0;
+
+ chan_list[n].seq_num = seq_num;
}
static void release_scid(const struct l2cap_frame *frame, uint16_t scid)
@@ -300,6 +310,16 @@ static uint16_t get_chan(const struct l2cap_frame *frame)
return i;
}
+static uint8_t get_seq_num(const struct l2cap_frame *frame)
+{
+ int i = get_chan_data_index(frame);
+
+ if (i < 0)
+ return 0;
+
+ return chan_list[i].seq_num;
+}
+
static void assign_ext_ctrl(const struct l2cap_frame *frame,
uint8_t ext_ctrl, uint16_t dcid)
{
@@ -510,11 +530,88 @@ static void print_conn_result(uint16_t result)
case 0x0004:
str = "Connection refused - no resources available";
break;
+ case 0x0006:
+ str = "Connection refused - Invalid Source CID";
+ break;
+ case 0x0007:
+ str = "Connection refused - Source CID already allocated";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result));
+}
+
+static void print_le_conn_result(uint16_t result)
+{
+ const char *str;
+
+ switch (le16_to_cpu(result)) {
+ case 0x0000:
+ str = "Connection successful";
+ break;
+ case 0x0002:
+ str = "Connection refused - PSM not supported";
+ break;
+ case 0x0004:
+ str = "Connection refused - no resources available";
+ break;
case 0x0005:
- str = "Insufficient Authentication";
+ str = "Connection refused - insufficient authentication";
break;
case 0x0006:
- str = "Insufficient Authorization";
+ str = "Connection refused - insufficient authorization";
+ break;
+ case 0x0007:
+ str = "Connection refused - insufficient encryption key size";
+ break;
+ case 0x0008:
+ str = "Connection refused - insufficient encryption";
+ break;
+ case 0x0009:
+ str = "Connection refused - Invalid Source CID";
+ break;
+ case 0x0010:
+ str = "Connection refused - Source CID already allocated";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result));
+}
+
+static void print_create_chan_result(uint16_t result)
+{
+ const char *str;
+
+ switch (le16_to_cpu(result)) {
+ case 0x0000:
+ str = "Connection successful";
+ break;
+ case 0x0001:
+ str = "Connection pending";
+ break;
+ case 0x0002:
+ str = "Connection refused - PSM not supported";
+ break;
+ case 0x0003:
+ str = "Connection refused - security block";
+ break;
+ case 0x0004:
+ str = "Connection refused - no resources available";
+ break;
+ case 0x0005:
+ str = "Connection refused - Controller ID not supported";
+ break;
+ case 0x0006:
+ str = "Connection refused - Invalid Source CID";
+ break;
+ case 0x0007:
+ str = "Connection refused - Source CID already allocated";
break;
default:
str = "Reserved";
@@ -613,7 +710,8 @@ static void print_config_options(const struct l2cap_frame *frame,
while (consumed < size - 2) {
const char *str = "Unknown";
- uint8_t type = data[consumed];
+ uint8_t type = data[consumed] & 0x7f;
+ uint8_t hint = data[consumed] & 0x80;
uint8_t len = data[consumed + 1];
uint8_t expect_len = 0;
int i;
@@ -626,7 +724,8 @@ static void print_config_options(const struct l2cap_frame *frame,
}
}
- print_field("Option: %s (0x%2.2x)", str, type);
+ print_field("Option: %s (0x%2.2x) [%s]", str, type,
+ hint ? "hint" : "mandatory");
if (expect_len == 0) {
consumed += 2;
@@ -1146,7 +1245,7 @@ static void sig_create_chan_rsp(const struct l2cap_frame *frame)
print_cid("Destination", pdu->dcid);
print_cid("Source", pdu->scid);
- print_conn_result(pdu->result);
+ print_create_chan_result(pdu->result);
print_conn_status(pdu->status);
assign_dcid(frame, le16_to_cpu(pdu->dcid), le16_to_cpu(pdu->scid));
@@ -1221,7 +1320,7 @@ static void sig_le_conn_rsp(const struct l2cap_frame *frame)
print_field("MTU: %u", le16_to_cpu(pdu->mtu));
print_field("MPS: %u", le16_to_cpu(pdu->mps));
print_field("Credits: %u", le16_to_cpu(pdu->credits));
- print_conn_result(pdu->result);
+ print_le_conn_result(pdu->result);
assign_dcid(frame, le16_to_cpu(pdu->dcid), 0);
}
@@ -1304,16 +1403,17 @@ static void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in,
uint16_t handle, uint8_t ident,
uint16_t cid, const void *data, uint16_t size)
{
- frame->index = index;
- frame->in = in;
- frame->handle = handle;
- frame->ident = ident;
- frame->cid = cid;
- frame->data = data;
- frame->size = size;
- frame->psm = get_psm(frame);
- frame->mode = get_mode(frame);
- frame->chan = get_chan(frame);
+ frame->index = index;
+ frame->in = in;
+ frame->handle = handle;
+ frame->ident = ident;
+ frame->cid = cid;
+ frame->data = data;
+ frame->size = size;
+ frame->psm = get_psm(frame);
+ frame->mode = get_mode(frame);
+ frame->chan = get_chan(frame);
+ frame->seq_num = get_seq_num(frame);
}
static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle,
@@ -2045,6 +2145,15 @@ static void att_error_response(const struct l2cap_frame *frame)
case 0x11:
str = "Insufficient Resources";
break;
+ case 0xfd:
+ str = "CCC Improperly Configured";
+ break;
+ case 0xfe:
+ str = "Procedure Already in Progress";
+ break;
+ case 0xff:
+ str = "Out of Range";
+ break;
default:
str = "Reserved";
break;
@@ -2207,12 +2316,35 @@ static void att_read_group_type_req(const struct l2cap_frame *frame)
print_uuid("Attribute group type", frame->data + 4, frame->size - 4);
}
+static void print_group_list(const char *label, uint8_t length,
+ const void *data, uint16_t size)
+{
+ uint8_t count;
+
+ if (length == 0)
+ return;
+
+ count = size / length;
+
+ print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");
+
+ while (size >= length) {
+ print_handle_range("Handle range", data);
+ print_uuid("UUID", data + 4, length - 4);
+
+ data += length;
+ size -= length;
+ }
+
+ packet_hexdump(data, size);
+}
+
static void att_read_group_type_rsp(const struct l2cap_frame *frame)
{
const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data;
print_field("Attribute data length: %d", pdu->length);
- print_data_list("Attribute data list", pdu->length,
+ print_group_list("Attribute group list", pdu->length,
frame->data + 1, frame->size - 1);
}
@@ -2286,6 +2418,13 @@ static void att_write_command(const struct l2cap_frame *frame)
print_hex_field(" Data", frame->data + 2, frame->size - 2);
}
+static void att_signed_write_command(const struct l2cap_frame *frame)
+{
+ print_field("Handle: 0x%4.4x", get_le16(frame->data));
+ print_hex_field(" Data", frame->data + 2, frame->size - 2 - 12);
+ print_hex_field(" Signature", frame->data + frame->size - 12, 12);
+}
+
struct att_opcode_data {
uint8_t opcode;
const char *str;
@@ -2347,7 +2486,7 @@ static const struct att_opcode_data att_opcode_table[] = {
att_handle_value_conf, 0, true },
{ 0x52, "Write Command",
att_write_command, 2, false },
- { 0xd2, "Signed Write Command" },
+ { 0xd2, "Signed Write Command", att_signed_write_command, 14, false },
{ }
};
@@ -2951,6 +3090,9 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
case 0x0003:
rfcomm_packet(&frame);
break;
+ case 0x000f:
+ bnep_packet(&frame);
+ break;
case 0x001f:
att_packet(index, in, handle, cid, data, size);
break;
@@ -2958,6 +3100,9 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
case 0x001B:
avctp_packet(&frame);
break;
+ case 0x0019:
+ avdtp_packet(&frame);
+ break;
default:
packet_hexdump(data, size);
break;
diff --git a/monitor/l2cap.h b/monitor/l2cap.h
index 711bcb16..813c7932 100644
--- a/monitor/l2cap.h
+++ b/monitor/l2cap.h
@@ -34,6 +34,7 @@ struct l2cap_frame {
uint16_t psm;
uint16_t chan;
uint8_t mode;
+ uint8_t seq_num;
const void *data;
uint16_t size;
};
@@ -153,6 +154,22 @@ static inline bool l2cap_frame_get_le64(struct l2cap_frame *frame,
return true;
}
+static inline bool l2cap_frame_get_be128(struct l2cap_frame *frame,
+ uint64_t *lvalue, uint64_t *rvalue)
+{
+ if (frame->size < (sizeof(*lvalue) + sizeof(*rvalue)))
+ return false;
+
+ if (lvalue && rvalue) {
+ *lvalue = get_be64(frame->data);
+ *rvalue = get_be64(frame->data);
+ }
+
+ l2cap_frame_pull(frame, frame, (sizeof(*lvalue) + sizeof(*rvalue)));
+
+ return true;
+}
+
void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags,
const void *data, uint16_t size);
diff --git a/monitor/ll.c b/monitor/ll.c
index e9d0cf6d..6212f79e 100644
--- a/monitor/ll.c
+++ b/monitor/ll.c
@@ -245,7 +245,7 @@ static void advertising_packet(const void *data, uint8_t size)
}
}
-static void data_packet(const void *data, uint8_t size)
+static void data_packet(const void *data, uint8_t size, bool padded)
{
const uint8_t *ptr = data;
uint8_t llid, length;
@@ -290,7 +290,7 @@ static void data_packet(const void *data, uint8_t size)
switch (llid) {
case 0x03:
- llcp_packet(data + 2, size - 2);
+ llcp_packet(data + 2, size - 2, padded);
break;
default:
@@ -299,7 +299,7 @@ static void data_packet(const void *data, uint8_t size)
}
}
-void ll_packet(uint16_t frequency, const void *data, uint8_t size)
+void ll_packet(uint16_t frequency, const void *data, uint8_t size, bool padded)
{
const struct bt_ll_hdr *hdr = data;
uint8_t channel = (frequency - 2402) / 2;
@@ -368,7 +368,7 @@ void ll_packet(uint16_t frequency, const void *data, uint8_t size)
if (access_addr == 0x8e89bed6)
advertising_packet(pdu_data, pdu_len);
else
- data_packet(pdu_data, pdu_len);
+ data_packet(pdu_data, pdu_len, padded);
}
static void null_pdu(const void *data, uint8_t size)
@@ -460,6 +460,21 @@ static void reject_ind(const void *data, uint8_t size)
packet_print_error("Error code", pdu->error);
}
+static void slave_feature_req(const void *data, uint8_t size)
+{
+ const struct bt_ll_slave_feature_req *pdu = data;
+
+ packet_print_features_ll(pdu->features);
+}
+
+static void reject_ind_ext(const void *data, uint8_t size)
+{
+ const struct bt_ll_reject_ind_ext *pdu = data;
+
+ print_field("Reject opcode: %u (0x%2.2x)", pdu->opcode, pdu->opcode);
+ packet_print_error("Error code", pdu->error);
+}
+
struct llcp_data {
uint8_t opcode;
const char *str;
@@ -469,22 +484,28 @@ struct llcp_data {
};
static const struct llcp_data llcp_table[] = {
- { 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
- { 0x01, "LL_CHANNEL_MAP_REQ", channel_map_req, 7, true },
- { 0x02, "LL_TERMINATE_IND", terminate_ind, 1, true },
- { 0x03, "LL_ENC_REQ", enc_req, 22, true },
- { 0x04, "LL_ENC_RSP", enc_rsp, 12, true },
- { 0x05, "LL_START_ENC_REQ", null_pdu, 0, true },
- { 0x06, "LL_START_ENC_RSP", null_pdu, 0, true },
- { 0x07, "LL_UNKNOWN_RSP", unknown_rsp, 1, true },
- { 0x08, "LL_FEATURE_REQ", feature_req, 8, true },
- { 0x09, "LL_FEATURE_RSP", feature_rsp, 8, true },
- { 0x0a, "LL_PAUSE_ENC_REQ", null_pdu, 0, true },
- { 0x0b, "LL_PAUSE_ENC_RSP", null_pdu, 0, true },
- { 0x0c, "LL_VERSION_IND", version_ind, 5, true },
- { 0x0d, "LL_REJECT_IND", reject_ind, 1, true },
- { 0x12, "LL_PING_REQ", null_pdu, 0, true },
- { 0x13, "LL_PING_RSP", null_pdu, 0, true },
+ { 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
+ { 0x01, "LL_CHANNEL_MAP_REQ", channel_map_req, 7, true },
+ { 0x02, "LL_TERMINATE_IND", terminate_ind, 1, true },
+ { 0x03, "LL_ENC_REQ", enc_req, 22, true },
+ { 0x04, "LL_ENC_RSP", enc_rsp, 12, true },
+ { 0x05, "LL_START_ENC_REQ", null_pdu, 0, true },
+ { 0x06, "LL_START_ENC_RSP", null_pdu, 0, true },
+ { 0x07, "LL_UNKNOWN_RSP", unknown_rsp, 1, true },
+ { 0x08, "LL_FEATURE_REQ", feature_req, 8, true },
+ { 0x09, "LL_FEATURE_RSP", feature_rsp, 8, true },
+ { 0x0a, "LL_PAUSE_ENC_REQ", null_pdu, 0, true },
+ { 0x0b, "LL_PAUSE_ENC_RSP", null_pdu, 0, true },
+ { 0x0c, "LL_VERSION_IND", version_ind, 5, true },
+ { 0x0d, "LL_REJECT_IND", reject_ind, 1, true },
+ { 0x0e, "LL_SLAVE_FEATURE_REQ", slave_feature_req, 8, true },
+ { 0x0f, "LL_CONNECTION_PARAM_REQ", NULL, 23, true },
+ { 0x10, "LL_CONNECTION_PARAM_RSP", NULL, 23, true },
+ { 0x11, "LL_REJECT_IND_EXT", reject_ind_ext, 2, true },
+ { 0x12, "LL_PING_REQ", null_pdu, 0, true },
+ { 0x13, "LL_PING_RSP", null_pdu, 0, true },
+ { 0x14, "LL_LENGTH_REQ", NULL, 8, true },
+ { 0x15, "LL_LENGTH_RSP", NULL, 8, true },
{ }
};
@@ -500,7 +521,7 @@ static const char *opcode_to_string(uint8_t opcode)
return "Unknown";
}
-void llcp_packet(const void *data, uint8_t size)
+void llcp_packet(const void *data, uint8_t size, bool padded)
{
uint8_t opcode = ((const uint8_t *) data)[0];
const struct llcp_data *llcp_data = NULL;
@@ -533,7 +554,7 @@ void llcp_packet(const void *data, uint8_t size)
return;
}
- if (llcp_data->fixed) {
+ if (llcp_data->fixed && !padded) {
if (size - 1 != llcp_data->size) {
print_text(COLOR_ERROR, "invalid packet size");
packet_hexdump(data + 1, size - 1);
diff --git a/monitor/ll.h b/monitor/ll.h
index ee28f40a..98e0bf48 100644
--- a/monitor/ll.h
+++ b/monitor/ll.h
@@ -24,5 +24,5 @@
#include <stdint.h>
-void ll_packet(uint16_t frequency, const void *data, uint8_t size);
-void llcp_packet(const void *data, uint8_t size);
+void ll_packet(uint16_t frequency, const void *data, uint8_t size, bool padded);
+void llcp_packet(const void *data, uint8_t size, bool padded);
diff --git a/monitor/lmp.c b/monitor/lmp.c
index 4a05973a..e7e6b25f 100644
--- a/monitor/lmp.c
+++ b/monitor/lmp.c
@@ -27,6 +27,7 @@
#endif
#include <stdio.h>
+#include <string.h>
#include "src/shared/util.h"
#include "display.h"
@@ -54,6 +55,26 @@ static void print_opcode(uint16_t opcode)
print_field("Operation: %s (%u)", str, opcode);
}
+static void name_req(const void *data, uint8_t size)
+{
+ const struct bt_lmp_name_req *pdu = data;
+
+ print_field("Offset: %u", pdu->offset);
+}
+
+static void name_rsp(const void *data, uint8_t size)
+{
+ const struct bt_lmp_name_rsp *pdu = data;
+ char str[15];
+
+ memcpy(str, pdu->fragment, 14);
+ str[14] = '\0';
+
+ print_field("Offset: %u", pdu->offset);
+ print_field("Length: %u", pdu->length);
+ print_field("Fragment: %s", str);
+}
+
static void accepted(const void *data, uint8_t size)
{
const struct bt_lmp_accepted *pdu = data;
@@ -73,6 +94,13 @@ static void clkoffset_req(const void *data, uint8_t size)
{
}
+static void clkoffset_rsp(const void *data, uint8_t size)
+{
+ const struct bt_lmp_clkoffset_rsp *pdu = data;
+
+ print_field("Clock offset: 0x%4.4x", le16_to_cpu(pdu->offset));
+}
+
static void detach(const void *data, uint8_t size)
{
const struct bt_lmp_detach *pdu = data;
@@ -135,6 +163,13 @@ static void stop_encryption_req(const void *data, uint8_t size)
{
}
+static void switch_req(const void *data, uint8_t size)
+{
+ const struct bt_lmp_switch_req *pdu = data;
+
+ print_field("Instant: 0x%8.8x", le32_to_cpu(pdu->instant));
+}
+
static void unsniff_req(const void *data, uint8_t size)
{
}
@@ -151,6 +186,67 @@ static void auto_rate(const void *data, uint8_t size)
{
}
+static void preferred_rate(const void *data, uint8_t size)
+{
+ const struct bt_lmp_preferred_rate *pdu = data;
+ const char *str;
+
+ str = (pdu->rate & 0x01) ? "do not use FEC" : "use FEC";
+
+ print_field("Basic data rate: %s (0x%02x)", str, pdu->rate & 0x01);
+
+ switch ((pdu->rate & 0x06) >> 1) {
+ case 0:
+ str = "No packet-size preference available";
+ break;
+ case 1:
+ str = "use 1-slot packets";
+ break;
+ case 2:
+ str = "use 3-slot packets";
+ break;
+ case 3:
+ str = "use 5-slot packets";
+ break;
+ }
+
+ print_field("Basic data rate: %s (0x%02x)", str, pdu->rate & 0x06);
+
+ switch ((pdu->rate & 0x11) >> 3) {
+ case 0:
+ str = "use DM1 packets";
+ break;
+ case 1:
+ str = "use 2 Mb/s packets";
+ break;
+ case 2:
+ str = "use 3 MB/s packets";
+ break;
+ case 3:
+ str = "reserved";
+ break;
+ }
+
+ print_field("Enhanced data rate: %s (0x%2.2x)", str, pdu->rate & 0x11);
+
+ switch ((pdu->rate & 0x60) >> 5) {
+ case 0:
+ str = "No packet-size preference available";
+ break;
+ case 1:
+ str = "use 1-slot packets";
+ break;
+ case 2:
+ str = "use 3-slot packets";
+ break;
+ case 3:
+ str = "use 5-slot packets";
+ break;
+ }
+
+ print_field("Enhanced data rate: %s (0x%2.2x)", str, pdu->rate & 0x60);
+}
+
static void version_req(const void *data, uint8_t size)
{
const struct bt_lmp_version_req *pdu = data;
@@ -221,6 +317,14 @@ static void host_connection_req(const void *data, uint8_t size)
{
}
+static void slot_offset(const void *data, uint8_t size)
+{
+ const struct bt_lmp_slot_offset *pdu = data;
+
+ print_field("Offset: %u usec", le16_to_cpu(pdu->offset));
+ packet_print_addr("Address", pdu->bdaddr, false);
+}
+
static void page_scan_mode_req(const void *data, uint8_t size)
{
const struct bt_lmp_page_scan_mode_req *pdu = data;
@@ -446,7 +550,7 @@ static void channel_classification(const void *data, uint8_t size)
for (i = 0; i < 10; i++)
sprintf(str + (i * 2), "%2.2x", pdu->classification[i]);
- print_field("Features: 0x%s", str);
+ print_field("Classification: 0x%s", str);
}
static void pause_encryption_req(const void *data, uint8_t size)
@@ -625,12 +729,12 @@ struct lmp_data {
};
static const struct lmp_data lmp_table[] = {
- { 1, "LMP_name_req" },
- { 2, "LMP_name_res" },
+ { 1, "LMP_name_req", name_req, 1, true },
+ { 2, "LMP_name_res", name_rsp, 16, true },
{ 3, "LMP_accepted", accepted, 1, true },
{ 4, "LMP_not_accepted", not_accepted, 2, true },
{ 5, "LMP_clkoffset_req", clkoffset_req, 0, true },
- { 6, "LMP_clkoffset_res" },
+ { 6, "LMP_clkoffset_res", clkoffset_rsp, 2, true },
{ 7, "LMP_detach", detach, 1, true },
{ 8, "LMP_in_rand" },
{ 9, "LMP_comb_key" },
@@ -643,7 +747,7 @@ static const struct lmp_data lmp_table[] = {
{ 16, "LMP_encryption_key_size_req", encryption_key_size_req, 1, true },
{ 17, "LMP_start_encryption_req", start_encryption_req, 16, true },
{ 18, "LMP_stop_encryption_req", stop_encryption_req, 0, true },
- { 19, "LMP_switch_req" },
+ { 19, "LMP_switch_req", switch_req, 4, true },
{ 20, "LMP_hold" },
{ 21, "LMP_hold_req" },
{ 22, "LMP_sniff" },
@@ -660,7 +764,7 @@ static const struct lmp_data lmp_table[] = {
{ 33, "LMP_max_power", max_power, 0, true },
{ 34, "LMP_min_power", min_power, 0, true },
{ 35, "LMP_auto_rate", auto_rate, 0, true },
- { 36, "LMP_preferred_rate" },
+ { 36, "LMP_preferred_rate", preferred_rate, 1, true },
{ 37, "LMP_version_req", version_req, 5, true },
{ 38, "LMP_version_res", version_res, 5, true },
{ 39, "LMP_features_req", features_req, 8, true },
@@ -676,7 +780,7 @@ static const struct lmp_data lmp_table[] = {
{ 49, "LMP_setup_complete", setup_complete, 0, true },
{ 50, "LMP_use_semi_permanent_key", use_semi_permanent_key, 0, true },
{ 51, "LMP_host_connection_req", host_connection_req, 0, true },
- { 52, "LMP_slot_offset" },
+ { 52, "LMP_slot_offset", slot_offset, 8, true },
{ 53, "LMP_page_mode_req" },
{ 54, "LMP_page_scan_mode_req", page_scan_mode_req, 2, true },
{ 55, "LMP_supervision_timeout" },
@@ -732,19 +836,27 @@ static const char *get_opcode_str(uint16_t opcode)
return NULL;
}
-void lmp_packet(const void *data, uint8_t size)
+void lmp_packet(const void *data, uint8_t size, bool padded)
{
const struct lmp_data *lmp_data = NULL;
const char *opcode_color, *opcode_str;
uint16_t opcode;
uint8_t tid, off;
+ const char *tid_str;
int i;
tid = ((const uint8_t *) data)[0] & 0x01;
opcode = (((const uint8_t *) data)[0] & 0xfe) >> 1;
+ tid_str = tid == 0x00 ? "Master" : "Slave";
+
switch (opcode) {
case 127:
+ if (size < 2) {
+ print_text(COLOR_ERROR, "extended opcode too short");
+ packet_hexdump(data, size);
+ return;
+ }
opcode = LMP_ESC4(((const uint8_t *) data)[1]);
off = 2;
break;
@@ -777,17 +889,19 @@ void lmp_packet(const void *data, uint8_t size)
if (opcode & 0xff00)
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
- " (%u/%u) TID %u", opcode >> 8, opcode & 0xff, tid);
+ " (%u/%u) %s transaction (%u)",
+ opcode >> 8, opcode & 0xff, tid_str, tid);
else
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
- " (%u) TID %d", opcode, tid);
+ " (%u) %s transaction (%d)",
+ opcode, tid_str, tid);
if (!lmp_data || !lmp_data->func) {
packet_hexdump(data + off, size - off);
return;
}
- if (lmp_data->fixed) {
+ if (lmp_data->fixed && !padded) {
if (size - off != lmp_data->size) {
print_text(COLOR_ERROR, "invalid packet size");
packet_hexdump(data + off, size - off);
diff --git a/monitor/lmp.h b/monitor/lmp.h
index 9b5393bd..9564c777 100644
--- a/monitor/lmp.h
+++ b/monitor/lmp.h
@@ -24,6 +24,6 @@
#include <stdint.h>
-void lmp_packet(const void *data, uint8_t size);
+void lmp_packet(const void *data, uint8_t size, bool padded);
void lmp_todo(void);
diff --git a/monitor/main.c b/monitor/main.c
index 90ecf35e..04577349 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -61,6 +61,7 @@ static void usage(void)
"\t-w, --write <file> Save traces in btsnoop format\n"
"\t-a, --analyze <file> Analyze traces in btsnoop format\n"
"\t-s, --server <socket> Start monitor server socket\n"
+ "\t-p, --priority <level> Show only priority or lower\n"
"\t-i, --index <num> Show only specified controller\n"
"\t-t, --time Show time instead of time offset\n"
"\t-T, --date Show time and date information\n"
@@ -78,6 +79,7 @@ static const struct option main_options[] = {
{ "write", required_argument, NULL, 'w' },
{ "analyze", required_argument, NULL, 'a' },
{ "server", required_argument, NULL, 's' },
+ { "priority",required_argument, NULL, 'p' },
{ "index", required_argument, NULL, 'i' },
{ "time", no_argument, NULL, 't' },
{ "date", no_argument, NULL, 'T' },
@@ -117,10 +119,10 @@ int main(int argc, char *argv[])
int opt;
#ifdef __TIZEN_PATCH__
- opt = getopt_long(argc, argv, "r:w:a:s:i:tTSE:C:W:vh",
+ opt = getopt_long(argc, argv, "r:w:a:s:p:i:tTSE:C:W:vh",
main_options, NULL);
#else
- opt = getopt_long(argc, argv, "r:w:a:s:i:tTSE:vh",
+ opt = getopt_long(argc, argv, "r:w:a:s:p:i:tTSE:vh",
main_options, NULL);
#endif
if (opt < 0)
@@ -139,6 +141,9 @@ int main(int argc, char *argv[])
case 's':
control_server(optarg);
break;
+ case 'p':
+ packet_set_priority(optarg);
+ break;
case 'i':
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
str = optarg + 3;
diff --git a/monitor/packet.c b/monitor/packet.c
index b2267a66..322bba69 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -36,6 +36,7 @@
#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
+#include <sys/socket.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
@@ -52,6 +53,8 @@
#include "l2cap.h"
#include "control.h"
#include "vendor.h"
+#include "intel.h"
+#include "broadcom.h"
#include "packet.h"
#define COLOR_INDEX_LABEL COLOR_WHITE
@@ -59,6 +62,10 @@
#define COLOR_NEW_INDEX COLOR_GREEN
#define COLOR_DEL_INDEX COLOR_RED
+#define COLOR_OPEN_INDEX COLOR_GREEN
+#define COLOR_CLOSE_INDEX COLOR_RED
+#define COLOR_INDEX_INFO COLOR_GREEN
+#define COLOR_VENDOR_DIAG COLOR_YELLOW
#define COLOR_HCI_COMMAND COLOR_BLUE
#define COLOR_HCI_COMMAND_UNKNOWN COLOR_WHITE_BG
@@ -80,11 +87,14 @@
#define COLOR_PHY_PACKET COLOR_BLUE
static time_t time_offset = ((time_t) -1);
+static int priority_level = BTSNOOP_PRIORITY_INFO;
static unsigned long filter_mask = 0;
static bool index_filter = false;
static uint16_t index_number = 0;
static uint16_t index_current = 0;
+#define UNKNOWN_MANUFACTURER 0xffff
+
#define MAX_CONN 16
struct conn_data {
@@ -150,6 +160,17 @@ void packet_del_filter(unsigned long filter)
filter_mask &= ~filter;
}
+void packet_set_priority(const char *priority)
+{
+ if (!priority)
+ return;
+
+ if (!strcasecmp(priority, "debug"))
+ priority_level = BTSNOOP_PRIORITY_DEBUG;
+ else
+ priority_level = atoi(priority);
+}
+
void packet_select_index(uint16_t index)
{
filter_mask &= ~PACKET_FILTER_SHOW_INDEX;
@@ -160,7 +181,8 @@ void packet_select_index(uint16_t index)
#define print_space(x) printf("%*c", (x), ' ');
-static void print_packet(struct timeval *tv, uint16_t index, char ident,
+static void print_packet(struct timeval *tv, struct ucred *cred,
+ uint16_t index, char ident,
const char *color, const char *label,
const char *text, const char *extra)
{
@@ -168,7 +190,8 @@ static void print_packet(struct timeval *tv, uint16_t index, char ident,
char line[256], ts_str[64];
int n, ts_len = 0, ts_pos = 0, len = 0, pos = 0;
- if (filter_mask & PACKET_FILTER_SHOW_INDEX) {
+ if ((filter_mask & PACKET_FILTER_SHOW_INDEX) &&
+ index != HCI_DEV_NONE) {
if (use_color()) {
n = sprintf(ts_str + ts_pos, "%s", COLOR_INDEX_LABEL);
if (n > 0)
@@ -234,7 +257,7 @@ static void print_packet(struct timeval *tv, uint16_t index, char ident,
pos += n;
}
- n = sprintf(line + pos, "%c %s", ident, label);
+ n = sprintf(line + pos, "%c %s", ident, label ? label : "");
if (n > 0) {
pos += n;
len += n;
@@ -244,7 +267,8 @@ static void print_packet(struct timeval *tv, uint16_t index, char ident,
int extra_len = extra ? strlen(extra) : 0;
int max_len = col - len - extra_len - ts_len - 3;
- n = snprintf(line + pos, max_len + 1, ": %s", text);
+ n = snprintf(line + pos, max_len + 1, "%s%s",
+ label ? ": " : "", text);
if (n > max_len) {
line[pos + max_len - 1] = '.';
line[pos + max_len - 2] = '.';
@@ -1229,7 +1253,7 @@ static void print_link_policy(uint16_t link_policy)
if (policy & 0x0004)
print_field(" Enable Sniff Mode");
if (policy & 0x0008)
- print_field(" Enabled Park State");
+ print_field(" Enable Park State");
}
static void print_air_mode(uint8_t mode)
@@ -2403,7 +2427,9 @@ static const struct {
uint16_t ver;
const char *str;
} broadcom_uart_subversion_table[] = {
+ { 0x210b, "BCM43142A0" }, /* 001.001.011 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
+ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ }
};
@@ -2433,6 +2459,7 @@ static void print_manufacturer_broadcom(uint16_t subversion, uint16_t revision)
switch ((rev & 0xf000) >> 12) {
case 0:
+ case 3:
for (i = 0; broadcom_uart_subversion_table[i].str; i++) {
if (broadcom_uart_subversion_table[i].ver == ver) {
str = broadcom_uart_subversion_table[i].str;
@@ -2453,11 +2480,11 @@ static void print_manufacturer_broadcom(uint16_t subversion, uint16_t revision)
if (str)
print_field(" Firmware: %3.3u.%3.3u.%3.3u (%s)",
- (ver & 0x7000) >> 13,
+ (ver & 0xe000) >> 13,
(ver & 0x1f00) >> 8, ver & 0x00ff, str);
else
print_field(" Firmware: %3.3u.%3.3u.%3.3u",
- (ver & 0x7000) >> 13,
+ (ver & 0xe000) >> 13,
(ver & 0x1f00) >> 8, ver & 0x00ff);
if (rev != 0xffff)
@@ -3557,6 +3584,53 @@ void packet_print_ad(const void *data, uint8_t size)
print_eir(data, size, true);
}
+struct broadcast_message {
+ uint32_t frame_sync_instant;
+ uint16_t bluetooth_clock_phase;
+ uint16_t left_open_offset;
+ uint16_t left_close_offset;
+ uint16_t right_open_offset;
+ uint16_t right_close_offset;
+ uint16_t frame_sync_period;
+ uint8_t frame_sync_period_fraction;
+} __attribute__ ((packed));
+
+static void print_3d_broadcast(const void *data, uint8_t size)
+{
+ const struct broadcast_message *msg = data;
+ uint32_t instant;
+ uint16_t left_open, left_close, right_open, right_close;
+ uint16_t phase, period;
+ uint8_t period_frac;
+ bool mode;
+
+ instant = le32_to_cpu(msg->frame_sync_instant);
+ mode = !!(instant & 0x40000000);
+ phase = le16_to_cpu(msg->bluetooth_clock_phase);
+ left_open = le16_to_cpu(msg->left_open_offset);
+ left_close = le16_to_cpu(msg->left_close_offset);
+ right_open = le16_to_cpu(msg->right_open_offset);
+ right_close = le16_to_cpu(msg->right_close_offset);
+ period = le16_to_cpu(msg->frame_sync_period);
+ period_frac = msg->frame_sync_period_fraction;
+
+ print_field(" Frame sync instant: 0x%8.8x", instant & 0x7fffffff);
+ print_field(" Video mode: %s (%d)", mode ? "Dual View" : "3D", mode);
+ print_field(" Bluetooth clock phase: %d usec (0x%4.4x)",
+ phase, phase);
+ print_field(" Left lense shutter open offset: %d usec (0x%4.4x)",
+ left_open, left_open);
+ print_field(" Left lense shutter close offset: %d usec (0x%4.4x)",
+ left_close, left_close);
+ print_field(" Right lense shutter open offset: %d usec (0x%4.4x)",
+ right_open, right_open);
+ print_field(" Right lense shutter close offset: %d usec (0x%4.4x)",
+ right_close, right_close);
+ print_field(" Frame sync period: %d.%d usec (0x%4.4x 0x%2.2x)",
+ period, period_frac * 256,
+ period, period_frac);
+}
+
void packet_hexdump(const unsigned char *buf, uint16_t len)
{
static const char hexdigits[] = "0123456789abcdef";
@@ -3596,7 +3670,8 @@ void packet_hexdump(const unsigned char *buf, uint16_t len)
}
}
-void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
+void packet_control(struct timeval *tv, struct ucred *cred,
+ uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
{
if (index_filter && index_number != index)
@@ -3614,17 +3689,23 @@ static int addr2str(const uint8_t *addr, char *str)
#define MAX_INDEX 16
struct index_data {
- uint8_t type;
- uint8_t bdaddr[6];
+ uint8_t type;
+ uint8_t bdaddr[6];
+ uint16_t manufacturer;
};
static struct index_data index_list[MAX_INDEX];
-void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
+void packet_monitor(struct timeval *tv, struct ucred *cred,
+ uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
{
const struct btsnoop_opcode_new_index *ni;
+ const struct btsnoop_opcode_index_info *ii;
+ const struct btsnoop_opcode_user_logging *ul;
char str[18], extra_str[24];
+ uint16_t manufacturer;
+ const char *ident;
if (index_filter && index_number != index)
return;
@@ -3641,6 +3722,7 @@ void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
if (index < MAX_INDEX) {
index_list[index].type = ni->type;
memcpy(index_list[index].bdaddr, ni->bdaddr, 6);
+ index_list[index].manufacturer = UNKNOWN_MANUFACTURER;
}
addr2str(ni->bdaddr, str);
@@ -3655,26 +3737,72 @@ void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
packet_del_index(tv, index, str);
break;
case BTSNOOP_OPCODE_COMMAND_PKT:
- packet_hci_command(tv, index, data, size);
+ packet_hci_command(tv, cred, index, data, size);
break;
case BTSNOOP_OPCODE_EVENT_PKT:
- packet_hci_event(tv, index, data, size);
+ packet_hci_event(tv, cred, index, data, size);
break;
case BTSNOOP_OPCODE_ACL_TX_PKT:
- packet_hci_acldata(tv, index, false, data, size);
+ packet_hci_acldata(tv, cred, index, false, data, size);
break;
case BTSNOOP_OPCODE_ACL_RX_PKT:
- packet_hci_acldata(tv, index, true, data, size);
+ packet_hci_acldata(tv, cred, index, true, data, size);
break;
case BTSNOOP_OPCODE_SCO_TX_PKT:
- packet_hci_scodata(tv, index, false, data, size);
+ packet_hci_scodata(tv, cred, index, false, data, size);
break;
case BTSNOOP_OPCODE_SCO_RX_PKT:
- packet_hci_scodata(tv, index, true, data, size);
+ packet_hci_scodata(tv, cred, index, true, data, size);
+ break;
+ case BTSNOOP_OPCODE_OPEN_INDEX:
+ if (index < MAX_INDEX)
+ addr2str(index_list[index].bdaddr, str);
+ else
+ sprintf(str, "00:00:00:00:00:00");
+
+ packet_open_index(tv, index, str);
+ break;
+ case BTSNOOP_OPCODE_CLOSE_INDEX:
+ if (index < MAX_INDEX)
+ addr2str(index_list[index].bdaddr, str);
+ else
+ sprintf(str, "00:00:00:00:00:00");
+
+ packet_close_index(tv, index, str);
+ break;
+ case BTSNOOP_OPCODE_INDEX_INFO:
+ ii = data;
+ manufacturer = le16_to_cpu(ii->manufacturer);
+
+ if (index < MAX_INDEX) {
+ memcpy(index_list[index].bdaddr, ii->bdaddr, 6);
+ index_list[index].manufacturer = manufacturer;
+ }
+
+ addr2str(ii->bdaddr, str);
+ packet_index_info(tv, index, str, manufacturer);
+ break;
+ case BTSNOOP_OPCODE_VENDOR_DIAG:
+ if (index < MAX_INDEX)
+ manufacturer = index_list[index].manufacturer;
+ else
+ manufacturer = UNKNOWN_MANUFACTURER;
+
+ packet_vendor_diag(tv, index, manufacturer, data, size);
+ break;
+ case BTSNOOP_OPCODE_SYSTEM_NOTE:
+ packet_system_note(tv, cred, index, data);
+ break;
+ case BTSNOOP_OPCODE_USER_LOGGING:
+ ul = data;
+ ident = ul->ident_len ? data + sizeof(*ul) : NULL;
+
+ packet_user_logging(tv, cred, index, ul->priority, ident,
+ data + sizeof(*ul) + ul->ident_len);
break;
default:
sprintf(extra_str, "(code %d len %d)", opcode, size);
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Unknown packet", NULL, extra_str);
packet_hexdump(data, size);
break;
@@ -3691,10 +3819,10 @@ void packet_simulator(struct timeval *tv, uint16_t frequency,
sprintf(str, "%u MHz", frequency);
- print_packet(tv, 0, '*', COLOR_PHY_PACKET,
+ print_packet(tv, NULL, 0, '*', COLOR_PHY_PACKET,
"Physical packet:", NULL, str);
- ll_packet(frequency, data, size);
+ ll_packet(frequency, data, size, false);
}
static void null_cmd(const void *data, uint8_t size)
@@ -5403,22 +5531,29 @@ static void write_ext_inquiry_length_cmd(const void *data, uint8_t size)
static void read_local_version_rsp(const void *data, uint8_t size)
{
const struct bt_hci_rsp_read_local_version *rsp = data;
+ uint16_t manufacturer;
print_status(rsp->status);
print_hci_version(rsp->hci_ver, rsp->hci_rev);
- switch (index_list[index_current].type) {
- case HCI_BREDR:
- print_lmp_version(rsp->lmp_ver, rsp->lmp_subver);
- break;
- case HCI_AMP:
- print_pal_version(rsp->lmp_ver, rsp->lmp_subver);
- break;
+ manufacturer = le16_to_cpu(rsp->manufacturer);
+
+ if (index_current < MAX_INDEX) {
+ switch (index_list[index_current].type) {
+ case HCI_BREDR:
+ print_lmp_version(rsp->lmp_ver, rsp->lmp_subver);
+ break;
+ case HCI_AMP:
+ print_pal_version(rsp->lmp_ver, rsp->lmp_subver);
+ break;
+ }
+
+ index_list[index_current].manufacturer = manufacturer;
}
print_manufacturer(rsp->manufacturer);
- switch (le16_to_cpu(rsp->manufacturer)) {
+ switch (manufacturer) {
case 15:
print_manufacturer_broadcom(rsp->lmp_subver, rsp->hci_rev);
break;
@@ -5498,6 +5633,9 @@ static void read_bd_addr_rsp(const void *data, uint8_t size)
print_status(rsp->status);
print_bdaddr(rsp->bdaddr);
+
+ if (index_current < MAX_INDEX)
+ memcpy(index_list[index_current].bdaddr, rsp->bdaddr, 6);
}
static void read_data_block_size_rsp(const void *data, uint8_t size)
@@ -6747,7 +6885,7 @@ static const struct opcode_data opcode_table[] = {
host_buffer_size_cmd, 7, true,
status_rsp, 1, true },
{ 0x0c35, 87, "Host Number of Completed Packets",
- host_num_completed_packets_cmd, 1, true },
+ host_num_completed_packets_cmd, 5, false },
{ 0x0c36, 88, "Read Link Supervision Timeout",
read_link_supv_timeout_cmd, 2, true,
read_link_supv_timeout_rsp, 5, true },
@@ -7148,6 +7286,63 @@ static const char *get_supported_command(int bit)
return NULL;
}
+static const char *current_vendor_str(void)
+{
+ uint16_t manufacturer;
+
+ if (index_current < MAX_INDEX)
+ manufacturer = index_list[index_current].manufacturer;
+ else
+ manufacturer = UNKNOWN_MANUFACTURER;
+
+ switch (manufacturer) {
+ case 2:
+ return "Intel";
+ case 15:
+ return "Broadcom";
+ }
+
+ return NULL;
+}
+
+static const struct vendor_ocf *current_vendor_ocf(uint16_t ocf)
+{
+ uint16_t manufacturer;
+
+ if (index_current < MAX_INDEX)
+ manufacturer = index_list[index_current].manufacturer;
+ else
+ manufacturer = UNKNOWN_MANUFACTURER;
+
+ switch (manufacturer) {
+ case 2:
+ return intel_vendor_ocf(ocf);
+ case 15:
+ return broadcom_vendor_ocf(ocf);
+ }
+
+ return NULL;
+}
+
+static const struct vendor_evt *current_vendor_evt(uint8_t evt)
+{
+ uint16_t manufacturer;
+
+ if (index_current < MAX_INDEX)
+ manufacturer = index_list[index_current].manufacturer;
+ else
+ manufacturer = UNKNOWN_MANUFACTURER;
+
+ switch (manufacturer) {
+ case 2:
+ return intel_vendor_evt(evt);
+ case 15:
+ return broadcom_vendor_evt(evt);
+ }
+
+ return NULL;
+}
+
static void inquiry_complete_evt(const void *data, uint8_t size)
{
const struct bt_hci_evt_inquiry_complete *evt = data;
@@ -7296,8 +7491,10 @@ static void cmd_complete_evt(const void *data, uint8_t size)
uint16_t opcode = le16_to_cpu(evt->opcode);
uint16_t ogf = cmd_opcode_ogf(opcode);
uint16_t ocf = cmd_opcode_ocf(opcode);
+ struct opcode_data vendor_data;
const struct opcode_data *opcode_data = NULL;
const char *opcode_color, *opcode_str;
+ char vendor_str[150];
int i;
for (i = 0; opcode_table[i].str; i++) {
@@ -7315,8 +7512,32 @@ static void cmd_complete_evt(const void *data, uint8_t size)
opcode_str = opcode_data->str;
} else {
if (ogf == 0x3f) {
- opcode_color = COLOR_HCI_COMMAND;
- opcode_str = "Vendor";
+ const struct vendor_ocf *vnd = current_vendor_ocf(ocf);
+
+ if (vnd) {
+ const char *str = current_vendor_str();
+
+ if (str) {
+ snprintf(vendor_str, sizeof(vendor_str),
+ "%s %s", str, vnd->str);
+ vendor_data.str = vendor_str;
+ } else
+ vendor_data.str = vnd->str;
+ vendor_data.rsp_func = vnd->rsp_func;
+ vendor_data.rsp_size = vnd->rsp_size;
+ vendor_data.rsp_fixed = vnd->rsp_fixed;
+
+ opcode_data = &vendor_data;
+
+ if (opcode_data->rsp_func)
+ opcode_color = COLOR_HCI_COMMAND;
+ else
+ opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+ opcode_str = opcode_data->str;
+ } else {
+ opcode_color = COLOR_HCI_COMMAND;
+ opcode_str = "Vendor";
+ }
} else {
opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
opcode_str = "Unknown";
@@ -7368,6 +7589,7 @@ static void cmd_status_evt(const void *data, uint8_t size)
uint16_t ocf = cmd_opcode_ocf(opcode);
const struct opcode_data *opcode_data = NULL;
const char *opcode_color, *opcode_str;
+ char vendor_str[150];
int i;
for (i = 0; opcode_table[i].str; i++) {
@@ -7382,8 +7604,23 @@ static void cmd_status_evt(const void *data, uint8_t size)
opcode_str = opcode_data->str;
} else {
if (ogf == 0x3f) {
- opcode_color = COLOR_HCI_COMMAND;
- opcode_str = "Vendor";
+ const struct vendor_ocf *vnd = current_vendor_ocf(ocf);
+
+ if (vnd) {
+ const char *str = current_vendor_str();
+
+ if (str) {
+ snprintf(vendor_str, sizeof(vendor_str),
+ "%s %s", str, vnd->str);
+ opcode_str = vendor_str;
+ } else
+ opcode_str = vnd->str;
+
+ opcode_color = COLOR_HCI_COMMAND;
+ } else {
+ opcode_color = COLOR_HCI_COMMAND;
+ opcode_str = "Vendor";
+ }
} else {
opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
opcode_str = "Unknown";
@@ -7443,11 +7680,15 @@ static void mode_change_evt(const void *data, uint8_t size)
static void return_link_keys_evt(const void *data, uint8_t size)
{
- uint8_t num_keys = *((uint8_t *) data);
+ const struct bt_hci_evt_return_link_keys *evt = data;
+ uint8_t i;
- print_field("Num keys: %d", num_keys);
+ print_field("Num keys: %d", evt->num_keys);
- packet_hexdump(data + 1, size - 1);
+ for (i = 0; i < evt->num_keys; i++) {
+ print_bdaddr(evt->keys + (i * 22));
+ print_link_key(evt->keys + (i * 22) + 6);
+ }
}
static void pin_code_request_evt(const void *data, uint8_t size)
@@ -7917,7 +8158,10 @@ static void slave_broadcast_receive_evt(const void *data, uint8_t size)
print_text(COLOR_ERROR, "invalid data size (%d != %d)",
size - 18, evt->length);
- packet_hexdump(data + 18, size - 18);
+ if (evt->lt_addr == 0x01 && evt->length == 17)
+ print_3d_broadcast(data + 18, size - 18);
+ else
+ packet_hexdump(data + 18, size - 18);
}
static void slave_broadcast_timeout_evt(const void *data, uint8_t size)
@@ -8128,7 +8372,42 @@ struct subevent_data {
bool fixed;
};
-static const struct subevent_data subevent_table[] = {
+static void print_subevent(const struct subevent_data *subevent_data,
+ const void *data, uint8_t size)
+{
+ const char *subevent_color;
+
+ if (subevent_data->func)
+ subevent_color = COLOR_HCI_EVENT;
+ else
+ subevent_color = COLOR_HCI_EVENT_UNKNOWN;
+
+ print_indent(6, subevent_color, "", subevent_data->str, COLOR_OFF,
+ " (0x%2.2x)", subevent_data->subevent);
+
+ if (!subevent_data->func) {
+ packet_hexdump(data, size);
+ return;
+ }
+
+ if (subevent_data->fixed) {
+ if (size != subevent_data->size) {
+ print_text(COLOR_ERROR, "invalid packet size");
+ packet_hexdump(data, size);
+ return;
+ }
+ } else {
+ if (size < subevent_data->size) {
+ print_text(COLOR_ERROR, "too short packet");
+ packet_hexdump(data, size);
+ return;
+ }
+ }
+
+ subevent_data->func(data, size);
+}
+
+static const struct subevent_data le_meta_event_table[] = {
{ 0x01, "LE Connection Complete",
le_conn_complete_evt, 18, true },
{ 0x02, "LE Advertising Report",
@@ -8157,56 +8436,58 @@ static const struct subevent_data subevent_table[] = {
static void le_meta_event_evt(const void *data, uint8_t size)
{
uint8_t subevent = *((const uint8_t *) data);
- const struct subevent_data *subevent_data = NULL;
- const char *subevent_color, *subevent_str;
+ struct subevent_data unknown;
+ const struct subevent_data *subevent_data = &unknown;
int i;
- for (i = 0; subevent_table[i].str; i++) {
- if (subevent_table[i].subevent == subevent) {
- subevent_data = &subevent_table[i];
+ unknown.subevent = subevent;
+ unknown.str = "Unknown";
+ unknown.func = NULL;
+ unknown.size = 0;
+ unknown.fixed = true;
+
+ for (i = 0; le_meta_event_table[i].str; i++) {
+ if (le_meta_event_table[i].subevent == subevent) {
+ subevent_data = &le_meta_event_table[i];
break;
}
}
- if (subevent_data) {
- if (subevent_data->func)
- subevent_color = COLOR_HCI_EVENT;
- else
- subevent_color = COLOR_HCI_EVENT_UNKNOWN;
- subevent_str = subevent_data->str;
- } else {
- subevent_color = COLOR_HCI_EVENT_UNKNOWN;
- subevent_str = "Unknown";
- }
+ print_subevent(subevent_data, data + 1, size - 1);
+}
- print_indent(6, subevent_color, "", subevent_str, COLOR_OFF,
- " (0x%2.2x)", subevent);
+static void vendor_evt(const void *data, uint8_t size)
+{
+ uint8_t subevent = *((const uint8_t *) data);
+ struct subevent_data vendor_data;
+ char vendor_str[150];
+ const struct vendor_evt *vnd = current_vendor_evt(subevent);
- if (!subevent_data || !subevent_data->func) {
- packet_hexdump(data + 1, size - 1);
- return;
- }
+ if (vnd) {
+ const char *str = current_vendor_str();
- if (subevent_data->fixed) {
- if (size - 1 != subevent_data->size) {
- print_text(COLOR_ERROR, "invalid packet size");
- packet_hexdump(data + 1, size - 1);
- return;
- }
+ if (str) {
+ snprintf(vendor_str, sizeof(vendor_str),
+ "%s %s", str, vnd->str);
+ vendor_data.str = vendor_str;
+ } else
+ vendor_data.str = vnd->str;
+ vendor_data.subevent = subevent;
+ vendor_data.func = vnd->evt_func;
+ vendor_data.size = vnd->evt_size;
+ vendor_data.fixed = vnd->evt_fixed;
+
+ print_subevent(&vendor_data, data + 1, size - 1);
} else {
- if (size - 1 < subevent_data->size) {
- print_text(COLOR_ERROR, "too short packet");
- packet_hexdump(data + 1, size - 1);
- return;
- }
- }
+ uint16_t manufacturer;
- subevent_data->func(data + 1, size - 1);
-}
+ if (index_current < MAX_INDEX)
+ manufacturer = index_list[index_current].manufacturer;
+ else
+ manufacturer = UNKNOWN_MANUFACTURER;
-static void vendor_evt(const void *data, uint8_t size)
-{
- vendor_event(0xffff, data, size);
+ vendor_event(manufacturer, data, size);
+ }
}
struct event_data {
@@ -8380,31 +8661,142 @@ void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
sprintf(details, "(%s,%s,%s)", hci_typetostr(type),
hci_bustostr(bus), name);
- print_packet(tv, index, '=', COLOR_NEW_INDEX, "New Index",
+ print_packet(tv, NULL, index, '=', COLOR_NEW_INDEX, "New Index",
label, details);
}
void packet_del_index(struct timeval *tv, uint16_t index, const char *label)
{
- print_packet(tv, index, '=', COLOR_DEL_INDEX, "Delete Index",
+ print_packet(tv, NULL, index, '=', COLOR_DEL_INDEX, "Delete Index",
+ label, NULL);
+}
+
+void packet_open_index(struct timeval *tv, uint16_t index, const char *label)
+{
+ print_packet(tv, NULL, index, '=', COLOR_OPEN_INDEX, "Open Index",
+ label, NULL);
+}
+
+void packet_close_index(struct timeval *tv, uint16_t index, const char *label)
+{
+ print_packet(tv, NULL, index, '=', COLOR_CLOSE_INDEX, "Close Index",
label, NULL);
}
-void packet_hci_command(struct timeval *tv, uint16_t index,
+void packet_index_info(struct timeval *tv, uint16_t index, const char *label,
+ uint16_t manufacturer)
+{
+ char details[128];
+
+ sprintf(details, "(%s)", bt_compidtostr(manufacturer));
+
+ print_packet(tv, NULL, index, '=', COLOR_INDEX_INFO, "Index Info",
+ label, details);
+}
+
+void packet_vendor_diag(struct timeval *tv, uint16_t index,
+ uint16_t manufacturer,
+ const void *data, uint16_t size)
+{
+ char extra_str[16];
+
+ sprintf(extra_str, "(len %d)", size);
+
+ print_packet(tv, NULL, index, '=', COLOR_VENDOR_DIAG,
+ "Vendor Diagnostic", NULL, extra_str);
+
+ switch (manufacturer) {
+ case 15:
+ broadcom_lm_diag(data, size);
+ break;
+ default:
+ packet_hexdump(data, size);
+ break;
+ }
+}
+
+void packet_system_note(struct timeval *tv, struct ucred *cred,
+ uint16_t index, const void *message)
+{
+ print_packet(tv, cred, index, '=', COLOR_INFO, "Note", message, NULL);
+}
+
+void packet_user_logging(struct timeval *tv, struct ucred *cred,
+ uint16_t index, uint8_t priority,
+ const char *ident, const char *message)
+{
+ char pid_str[128];
+ const char *label;
+ const char *color;
+
+ if (priority > priority_level)
+ return;
+
+ switch (priority) {
+ case BTSNOOP_PRIORITY_ERR:
+ color = COLOR_ERROR;
+ break;
+ case BTSNOOP_PRIORITY_WARNING:
+ color = COLOR_WARN;
+ break;
+ case BTSNOOP_PRIORITY_INFO:
+ color = COLOR_INFO;
+ break;
+ case BTSNOOP_PRIORITY_DEBUG:
+ color = COLOR_DEBUG;
+ break;
+ default:
+ color = COLOR_WHITE_BG;
+ break;
+ }
+
+ if (cred) {
+ char *path = alloca(24);
+ char line[128];
+ FILE *fp;
+
+ snprintf(path, 23, "/proc/%u/comm", cred->pid);
+
+ fp = fopen(path, "re");
+ if (fp) {
+ if (fgets(line, sizeof(line), fp)) {
+ line[strcspn(line, "\r\n")] = '\0';
+ snprintf(pid_str, sizeof(pid_str), "%s[%u]",
+ line, cred->pid);
+ } else
+ snprintf(pid_str, sizeof(pid_str), "%u",
+ cred->pid);
+ fclose(fp);
+ } else
+ snprintf(pid_str, sizeof(pid_str), "%u", cred->pid);
+
+ label = pid_str;
+ } else {
+ if (ident)
+ label = ident;
+ else
+ label = "Message";
+ }
+
+ print_packet(tv, cred, index, '=', color, label, message, NULL);
+}
+
+void packet_hci_command(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size)
{
const hci_command_hdr *hdr = data;
uint16_t opcode = le16_to_cpu(hdr->opcode);
uint16_t ogf = cmd_opcode_ogf(opcode);
uint16_t ocf = cmd_opcode_ocf(opcode);
+ struct opcode_data vendor_data;
const struct opcode_data *opcode_data = NULL;
const char *opcode_color, *opcode_str;
- char extra_str[25];
+ char extra_str[25], vendor_str[150];
int i;
if (size < HCI_COMMAND_HDR_SIZE) {
sprintf(extra_str, "(len %d)", size);
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Malformed HCI Command packet", NULL, extra_str);
packet_hexdump(data, size);
return;
@@ -8428,8 +8820,32 @@ void packet_hci_command(struct timeval *tv, uint16_t index,
opcode_str = opcode_data->str;
} else {
if (ogf == 0x3f) {
- opcode_color = COLOR_HCI_COMMAND;
- opcode_str = "Vendor";
+ const struct vendor_ocf *vnd = current_vendor_ocf(ocf);
+
+ if (vnd) {
+ const char *str = current_vendor_str();
+
+ if (str) {
+ snprintf(vendor_str, sizeof(vendor_str),
+ "%s %s", str, vnd->str);
+ vendor_data.str = vendor_str;
+ } else
+ vendor_data.str = vnd->str;
+ vendor_data.cmd_func = vnd->cmd_func;
+ vendor_data.cmd_size = vnd->cmd_size;
+ vendor_data.cmd_fixed = vnd->cmd_fixed;
+
+ opcode_data = &vendor_data;
+
+ if (opcode_data->cmd_func)
+ opcode_color = COLOR_HCI_COMMAND;
+ else
+ opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+ opcode_str = opcode_data->str;
+ } else {
+ opcode_color = COLOR_HCI_COMMAND;
+ opcode_str = "Vendor";
+ }
} else {
opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
opcode_str = "Unknown";
@@ -8438,7 +8854,7 @@ void packet_hci_command(struct timeval *tv, uint16_t index,
sprintf(extra_str, "(0x%2.2x|0x%4.4x) plen %d", ogf, ocf, hdr->plen);
- print_packet(tv, index, '<', opcode_color, "HCI Command",
+ print_packet(tv, cred, index, '<', opcode_color, "HCI Command",
opcode_str, extra_str);
if (!opcode_data || !opcode_data->cmd_func) {
@@ -8470,7 +8886,7 @@ void packet_hci_command(struct timeval *tv, uint16_t index,
opcode_data->cmd_func(data, hdr->plen);
}
-void packet_hci_event(struct timeval *tv, uint16_t index,
+void packet_hci_event(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size)
{
const hci_event_hdr *hdr = data;
@@ -8481,7 +8897,7 @@ void packet_hci_event(struct timeval *tv, uint16_t index,
if (size < HCI_EVENT_HDR_SIZE) {
sprintf(extra_str, "(len %d)", size);
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Malformed HCI Event packet", NULL, extra_str);
packet_hexdump(data, size);
return;
@@ -8510,7 +8926,7 @@ void packet_hci_event(struct timeval *tv, uint16_t index,
sprintf(extra_str, "(0x%2.2x) plen %d", hdr->evt, hdr->plen);
- print_packet(tv, index, '>', event_color, "HCI Event",
+ print_packet(tv, cred, index, '>', event_color, "HCI Event",
event_str, extra_str);
if (!event_data || !event_data->func) {
@@ -8542,8 +8958,8 @@ void packet_hci_event(struct timeval *tv, uint16_t index,
event_data->func(data, hdr->plen);
}
-void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
- const void *data, uint16_t size)
+void packet_hci_acldata(struct timeval *tv, struct ucred *cred, uint16_t index,
+ bool in, const void *data, uint16_t size)
{
const struct bt_hci_acl_hdr *hdr = data;
uint16_t handle = le16_to_cpu(hdr->handle);
@@ -8553,10 +8969,10 @@ void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
if (size < sizeof(*hdr)) {
if (in)
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Malformed ACL Data RX packet", NULL, NULL);
else
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Malformed ACL Data TX packet", NULL, NULL);
packet_hexdump(data, size);
return;
@@ -8568,7 +8984,7 @@ void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
sprintf(handle_str, "Handle %d", acl_handle(handle));
sprintf(extra_str, "flags 0x%2.2x dlen %d", flags, dlen);
- print_packet(tv, index, in ? '>' : '<', COLOR_HCI_ACLDATA,
+ print_packet(tv, cred, index, in ? '>' : '<', COLOR_HCI_ACLDATA,
in ? "ACL Data RX" : "ACL Data TX",
handle_str, extra_str);
@@ -8585,8 +9001,8 @@ void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
l2cap_packet(index, in, acl_handle(handle), flags, data, size);
}
-void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
- const void *data, uint16_t size)
+void packet_hci_scodata(struct timeval *tv, struct ucred *cred, uint16_t index,
+ bool in, const void *data, uint16_t size)
{
const hci_sco_hdr *hdr = data;
uint16_t handle = le16_to_cpu(hdr->handle);
@@ -8595,10 +9011,10 @@ void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
if (size < HCI_SCO_HDR_SIZE) {
if (in)
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Malformed SCO Data RX packet", NULL, NULL);
else
- print_packet(tv, index, '*', COLOR_ERROR,
+ print_packet(tv, cred, index, '*', COLOR_ERROR,
"Malformed SCO Data TX packet", NULL, NULL);
packet_hexdump(data, size);
return;
@@ -8610,7 +9026,7 @@ void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
sprintf(handle_str, "Handle %d", acl_handle(handle));
sprintf(extra_str, "flags 0x%2.2x dlen %d", flags, hdr->dlen);
- print_packet(tv, index, in ? '>' : '<', COLOR_HCI_SCODATA,
+ print_packet(tv, cred, index, in ? '>' : '<', COLOR_HCI_SCODATA,
in ? "SCO Data RX" : "SCO Data TX",
handle_str, extra_str);
@@ -8650,10 +9066,10 @@ void packet_todo(void)
printf("\t%s\n", event_table[i].str);
}
- for (i = 0; subevent_table[i].str; i++) {
- if (subevent_table[i].func)
+ for (i = 0; le_meta_event_table[i].str; i++) {
+ if (le_meta_event_table[i].func)
continue;
- printf("\t%s\n", subevent_table[i].str);
+ printf("\t%s\n", le_meta_event_table[i].str);
}
}
diff --git a/monitor/packet.h b/monitor/packet.h
index c39816bc..322f1019 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <sys/time.h>
+#include <sys/socket.h>
#define PACKET_FILTER_SHOW_INDEX (1 << 0)
#define PACKET_FILTER_SHOW_DATE (1 << 1)
@@ -37,6 +38,7 @@ void packet_set_filter(unsigned long filter);
void packet_add_filter(unsigned long filter);
void packet_del_filter(unsigned long filter);
+void packet_set_priority(const char *priority);
void packet_select_index(uint16_t index);
void packet_hexdump(const unsigned char *buf, uint16_t len);
@@ -53,9 +55,11 @@ void packet_print_channel_map_ll(const uint8_t *map);
void packet_print_io_capability(uint8_t capability);
void packet_print_io_authentication(uint8_t authentication);
-void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
+void packet_control(struct timeval *tv, struct ucred *cred,
+ uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
-void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
+void packet_monitor(struct timeval *tv, struct ucred *cred,
+ uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void packet_simulator(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size);
@@ -63,14 +67,26 @@ void packet_simulator(struct timeval *tv, uint16_t frequency,
void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
uint8_t type, uint8_t bus, const char *name);
void packet_del_index(struct timeval *tv, uint16_t index, const char *label);
-
-void packet_hci_command(struct timeval *tv, uint16_t index,
- const void *data, uint16_t size);
-void packet_hci_event(struct timeval *tv, uint16_t index,
+void packet_open_index(struct timeval *tv, uint16_t index, const char *label);
+void packet_close_index(struct timeval *tv, uint16_t index, const char *label);
+void packet_index_info(struct timeval *tv, uint16_t index, const char *label,
+ uint16_t manufacturer);
+void packet_vendor_diag(struct timeval *tv, uint16_t index,
+ uint16_t manufacturer,
const void *data, uint16_t size);
-void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
+void packet_system_note(struct timeval *tv, struct ucred *cred,
+ uint16_t index, const void *message);
+void packet_user_logging(struct timeval *tv, struct ucred *cred,
+ uint16_t index, uint8_t priority,
+ const char *ident, const char *message);
+
+void packet_hci_command(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size);
-void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
+void packet_hci_event(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size);
+void packet_hci_acldata(struct timeval *tv, struct ucred *cred, uint16_t index,
+ bool in, const void *data, uint16_t size);
+void packet_hci_scodata(struct timeval *tv, struct ucred *cred, uint16_t index,
+ bool in, const void *data, uint16_t size);
void packet_todo(void);
diff --git a/monitor/rfcomm.c b/monitor/rfcomm.c
index bdf40006..b32ad40a 100644
--- a/monitor/rfcomm.c
+++ b/monitor/rfcomm.c
@@ -367,7 +367,7 @@ static inline bool mcc_frame(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
else
type_str = "Unknown";
- print_field("%*cMCC Message type: %s %s(0x%2.2x)", indent, ' ',
+ print_field("%*cMCC Message type: %s %s (0x%2.2x)", indent, ' ',
type_str, CR_STR(mcc.type), type);
print_field("%*cLength: %d", indent+2, ' ', mcc.length);
@@ -421,7 +421,7 @@ struct rfcomm_data {
};
static const struct rfcomm_data rfcomm_table[] = {
- { 0x2f, "Set Async Balance Mode (SABM) " },
+ { 0x2f, "Set Async Balance Mode (SABM)" },
{ 0x63, "Unnumbered Ack (UA)" },
{ 0x0f, "Disconnect Mode (DM)" },
{ 0x43, "Disconnect (DISC)" },
@@ -493,7 +493,7 @@ void rfcomm_packet(const struct l2cap_frame *frame)
}
print_indent(6, frame_color, "RFCOMM: ", frame_str, COLOR_OFF,
- "(0x%2.2x)", ctype);
+ " (0x%2.2x)", ctype);
rfcomm_frame.hdr = hdr;
print_rfcomm_hdr(&rfcomm_frame, indent);
diff --git a/monitor/uuid.c b/monitor/uuid.c
index 1912661f..b123ebeb 100644
--- a/monitor/uuid.c
+++ b/monitor/uuid.c
@@ -161,7 +161,15 @@ static struct {
{ 0x181b, "Body Composition" },
{ 0x181c, "User Data" },
{ 0x181d, "Weight Scale" },
- /* 0x181e to 0x27ff undefined */
+ { 0x181e, "Bond Management" },
+ { 0x181f, "Continuous Glucose Monitoring" },
+ { 0x1820, "Internet Protocol Support" },
+ { 0x1821, "Indoor Positioning" },
+ { 0x1822, "Pulse Oximeter" },
+ { 0x1823, "HTTP Proxy" },
+ { 0x1824, "Transport Discovery" },
+ { 0x1825, "Object Transfer" },
+ /* 0x1824 to 0x27ff undefined */
{ 0x2800, "Primary Service" },
{ 0x2801, "Secondary Service" },
{ 0x2802, "Include" },
@@ -334,6 +342,180 @@ static struct {
{ 0x2aa1, "Magnetic Flux Density - 3D" },
{ 0x2aa2, "Language" },
{ 0x2aa3, "Barometric Pressure Trend" },
+ { 0x2aa4, "Bond Management Control Point" },
+ { 0x2aa5, "Bond Management Feature" },
+ { 0x2aa6, "Central Address Resolution" },
+ { 0x2aa7, "CGM Measurement" },
+ { 0x2aa8, "CGM Feature" },
+ { 0x2aa9, "CGM Status" },
+ { 0x2aaa, "CGM Session Start Time" },
+ { 0x2aab, "CGM Session Run Time" },
+ { 0x2aac, "CGM Specific Ops Control Point" },
+ { 0x2aad, "Indoor Positioning Configuration" },
+ { 0x2aae, "Latitude" },
+ { 0x2aaf, "Longitude" },
+ { 0x2ab0, "Local North Coordinate" },
+ { 0x2ab1, "Local East Coordinate" },
+ { 0x2ab2, "Floor Number" },
+ { 0x2ab3, "Altitude" },
+ { 0x2ab4, "Uncertainty" },
+ { 0x2ab5, "Location Name" },
+ { 0x2ab6, "URI" },
+ { 0x2ab7, "HTTP Headers" },
+ { 0x2ab8, "HTTP Status Code" },
+ { 0x2ab9, "HTTP Entity Body" },
+ { 0x2aba, "HTTP Control Point" },
+ { 0x2abb, "HTTPS Security" },
+ { 0x2abc, "TDS Control Point" },
+ { 0x2abd, "OTS Feature" },
+ { 0x2abe, "Object Name" },
+ { 0x2abf, "Object Type" },
+ { 0x2ac0, "Object Size" },
+ { 0x2ac1, "Object First-Created" },
+ { 0x2ac2, "Object Last-Modified" },
+ { 0x2ac3, "Object ID" },
+ { 0x2ac4, "Object Properties" },
+ { 0x2ac5, "Object Action Control Point" },
+ { 0x2ac6, "Object List Control Point" },
+ { 0x2ac7, "Object List Filter" },
+ { 0x2ac8, "Object Changed" },
+ /* vendor defined */
+ { 0xfeff, "GN Netcom" },
+ { 0xfefe, "GN ReSound A/S" },
+ { 0xfefd, "Gimbal, Inc." },
+ { 0xfefc, "Gimbal, Inc." },
+ { 0xfefb, "Stollmann E+V GmbH" },
+ { 0xfefa, "PayPal, Inc." },
+ { 0xfef9, "PayPal, Inc." },
+ { 0xfef8, "Aplix Corporation" },
+ { 0xfef7, "Aplix Corporation" },
+ { 0xfef6, "Wicentric, Inc." },
+ { 0xfef5, "Dialog Semiconductor GmbH" },
+ { 0xfef4, "Google" },
+ { 0xfef3, "Google" },
+ { 0xfef2, "CSR" },
+ { 0xfef1, "CSR" },
+ { 0xfef0, "Intel" },
+ { 0xfeef, "Polar Electro Oy" },
+ { 0xfeee, "Polar Electro Oy" },
+ { 0xfeed, "Tile, Inc." },
+ { 0xfeec, "Tile, Inc." },
+ { 0xfeeb, "Swirl Networks, Inc." },
+ { 0xfeea, "Swirl Networks, Inc." },
+ { 0xfee9, "Quintic Corp." },
+ { 0xfee8, "Quintic Corp." },
+ { 0xfee7, "Tencent Holdings Limited" },
+ { 0xfee6, "Seed Labs, Inc." },
+ { 0xfee5, "Nordic Semiconductor ASA" },
+ { 0xfee4, "Nordic Semiconductor ASA" },
+ { 0xfee3, "Anki, Inc." },
+ { 0xfee2, "Anki, Inc." },
+ { 0xfee1, "Anhui Huami Information Technology Co." },
+ { 0xfee0, "Anhui Huami Information Technology Co." },
+ { 0xfedf, "Design SHIFT" },
+ { 0xfede, "Coin, Inc." },
+ { 0xfedd, "Jawbone" },
+ { 0xfedc, "Jawbone" },
+ { 0xfedb, "Perka, Inc." },
+ { 0xfeda, "ISSC Technologies Corporation" },
+ { 0xfed9, "Pebble Technology Corporation" },
+ { 0xfed8, "Google" },
+ { 0xfed7, "Broadcom Corporation" },
+ { 0xfed6, "Broadcom Corporation" },
+ { 0xfed5, "Plantronics Inc." },
+ { 0xfed4, "Apple, Inc." },
+ { 0xfed3, "Apple, Inc." },
+ { 0xfed2, "Apple, Inc." },
+ { 0xfed1, "Apple, Inc." },
+ { 0xfed0, "Apple, Inc." },
+ { 0xfecf, "Apple, Inc." },
+ { 0xfece, "Apple, Inc." },
+ { 0xfecd, "Apple, Inc." },
+ { 0xfecc, "Apple, Inc." },
+ { 0xfecb, "Apple, Inc." },
+ { 0xfeca, "Apple, Inc." },
+ { 0xfec9, "Apple, Inc." },
+ { 0xfec8, "Apple, Inc." },
+ { 0xfec7, "Apple, Inc." },
+ { 0xfec6, "Kocomojo, LLC" },
+ { 0xfec5, "Realtek Semiconductor Corp." },
+ { 0xfec4, "PLUS Location Systems" },
+ { 0xfec3, "360fly, Inc." },
+ { 0xfec2, "Blue Spark Technologies, Inc." },
+ { 0xfec1, "KDDI Corporation" },
+ { 0xfec0, "KDDI Corporation" },
+ { 0xfebf, "Nod, Inc." },
+ { 0xfebe, "Bose Corporation" },
+ { 0xfebd, "Clover Network, Inc." },
+ { 0xfebc, "Dexcom, Inc." },
+ { 0xfebb, "adafruit industries" },
+ { 0xfeba, "Tencent Holdings Limited" },
+ { 0xfeb9, "LG Electronics" },
+ { 0xfeb8, "Facebook, Inc." },
+ { 0xfeb7, "Facebook, Inc." },
+ { 0xfeb6, "Vencer Co, Ltd" },
+ { 0xfeb5, "WiSilica Inc." },
+ { 0xfeb4, "WiSilica Inc." },
+ { 0xfeb3, "Taobao" },
+ { 0xfeb2, "Microsoft Corporation" },
+ { 0xfeb1, "Electronics Tomorrow Limited" },
+ { 0xfeb0, "Nest Labs Inc." },
+ { 0xfeaf, "Nest Labs Inc." },
+ { 0xfeae, "Nokia Corporation" },
+ { 0xfead, "Nokia Corporation" },
+ { 0xfeac, "Nokia Corporation" },
+ { 0xfeab, "Nokia Corporation" },
+ { 0xfeaa, "Google" },
+ { 0xfea9, "Savant Systems LLC" },
+ { 0xfea8, "Savant Systems LLC" },
+ { 0xfea7, "UTC Fire and Security" },
+ { 0xfea6, "GoPro, Inc." },
+ { 0xfea5, "GoPro, Inc." },
+ { 0xfea4, "Paxton Access Ltd" },
+ { 0xfea3, "ITT Industries" },
+ { 0xfea2, "Intrepid Control Systems, Inc." },
+ { 0xfea1, "Intrepid Control Systems, Inc." },
+ { 0xfea0, "Google" },
+ { 0xfe9f, "Google" },
+ { 0xfe9e, "Dialog Semiconductor B.V." },
+ { 0xfe9d, "Mobiquity Networks Inc" },
+ { 0xfe9c, "GSI Laboratories, Inc." },
+ { 0xfe9b, "Samsara Networks, Inc" },
+ { 0xfe9a, "Estimote" },
+ { 0xfe99, "Currant, Inc." },
+ { 0xfe98, "Currant, Inc." },
+ { 0xfe97, "Tesla Motor Inc." },
+ { 0xfe96, "Tesla Motor Inc." },
+ { 0xfe95, "Xiaomi Inc." },
+ { 0xfe94, "OttoQ Inc." },
+ { 0xfe93, "OttoQ Inc." },
+ { 0xfe92, "Jarden Safety & Security" },
+ { 0xfe91, "Shanghai Imilab Technology Co.,Ltd" },
+ { 0xfe90, "JUMA" },
+ { 0xfe8f, "CSR" },
+ { 0xfe8e, "ARM Ltd" },
+ { 0xfe8d, "Interaxon Inc." },
+ { 0xfe8c, "TRON Forum" },
+ { 0xfe8b, "Apple, Inc." },
+ { 0xfe8a, "Apple, Inc." },
+ { 0xfe89, "B&O Play A/S" },
+ { 0xfe88, "SALTO SYSTEMS S.L." },
+ { 0xfe87, "Qingdao Yeelink Information Technology Co., Ltd. ( 青岛亿联客信息技术有限公司 )" },
+ { 0xfe86, "HUAWEI Technologies Co., Ltd. ( 华为技术有限公司 )" },
+ { 0xfe85, "RF Digital Corp" },
+ { 0xfe84, "RF Digital Corp" },
+ { 0xfe83, "Blue Bite" },
+ { 0xfe82, "Medtronic Inc." },
+ { 0xfe81, "Medtronic Inc." },
+ { 0xfe80, "Doppler Lab" },
+ { 0xfe7f, "Doppler Lab" },
+ { 0xfe7e, "Awear Solutions Ltd" },
+ { 0xfe7d, "Aterica Health Inc." },
+ { 0xfe7c, "Stollmann E+V GmbH" },
+ { 0xfe7b, "Orion Labs, Inc." },
+ /* SDO defined */
+ { 0xfffe, "Alliance for Wireless Power (A4WP)" },
+ { 0xfffd, "Fast IDentity Online Alliance (FIDO)" },
{ }
};
diff --git a/monitor/vendor.h b/monitor/vendor.h
index 9ac9a4bf..f5792b3c 100644
--- a/monitor/vendor.h
+++ b/monitor/vendor.h
@@ -24,4 +24,23 @@
#include <stdint.h>
+struct vendor_ocf {
+ uint16_t ocf;
+ const char *str;
+ void (*cmd_func) (const void *data, uint8_t size);
+ uint8_t cmd_size;
+ bool cmd_fixed;
+ void (*rsp_func) (const void *data, uint8_t size);
+ uint8_t rsp_size;
+ bool rsp_fixed;
+};
+
+struct vendor_evt {
+ uint8_t evt;
+ const char *str;
+ void (*evt_func) (const void *data, uint8_t size);
+ uint8_t evt_size;
+ bool evt_fixed;
+};
+
void vendor_event(uint16_t manufacturer, const void *data, uint8_t size);
diff --git a/obexd.manifest b/obexd.manifest
index 75b0fa5e..9d334de1 100644
--- a/obexd.manifest
+++ b/obexd.manifest
@@ -1,5 +1,29 @@
<manifest>
+ <define>
+ <domain name="obexd"/>
+ <request>
+ <smack request="system::vconf" type="rwxat"/>
+ <smack request="system::share" type="rwxat"/>
+ <smack request="system::ext_storage" type="rwxat"/>
+ <smack request="system::media" type="rwxat"/>
+ <smack request="sys-assert::core" type="rwxat"/>
+ <smack request="ui-gadget::client" type="rwx"/>
+ <smack request="map-agent::dbus" type="rwxat"/>
+ <smack request="pb-agent::dbus" type="rwxat"/>
+ <smack request="dbus" type="rwx"/>
+ <smack request="syslogd" type="w"/>
+ <smack request="sysklogd" type="w"/>
+ <smack request="bluez" type="rw"/>
+ </request>
+ <permit>
+ <smack permit="dbus" type="rwx"/>
+ </permit>
+ </define>
+ <assign>
+ <filesystem path="/usr/lib/obex/plugins/" label="_"/>
+ <filesystem path="/usr/share/dbus-1/services/org.bluez.obex.service" label="_"/>
+ </assign>
<request>
- <domain name="_"/>
+ <domain name="obexd"/>
</request>
</manifest>
diff --git a/obexd/client/manager.c b/obexd/client/manager.c
index c54bed0a..8eaceafd 100644
--- a/obexd/client/manager.c
+++ b/obexd/client/manager.c
@@ -172,6 +172,7 @@ static struct obc_session *find_session(const char *path)
#endif
for (l = sessions; l; l = l->next) {
struct obc_session *session = l->data;
+
if (g_strcmp0(obc_session_get_path(session), path) == 0)
return session;
}
diff --git a/obexd/client/mns-tizen.c b/obexd/client/mns-tizen.c
index b254cd3a..49522259 100644
--- a/obexd/client/mns-tizen.c
+++ b/obexd/client/mns-tizen.c
@@ -30,8 +30,6 @@
#include <string.h>
#include "log.h"
-#include "gobex/gobex.h"
-#include "gobex/gobex-apparam.h"
#include "transfer.h"
#include "session.h"
@@ -137,8 +135,7 @@ static DBusMessage *send_event(DBusConnection *connection,
{
struct mns_data *mns = user_data;
struct obc_transfer *transfer;
- guint8 masinstanceid;
- GObexApparam *apparam;
+ struct sendevent_apparam apparam;
gchar *event_type;
gchar *folder;
gchar *old_folder;
@@ -173,12 +170,12 @@ static DBusMessage *send_event(DBusConnection *connection,
if (transfer == NULL)
goto fail;
+ apparam.masinstanceid_tag = MAP_AP_MASINSTANCEID;
+ apparam.masinstanceid_len = 1;
/* Obexd currently supports single SDP for MAS */
- masinstanceid = 0;
- apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_MASINSTANCEID,
- masinstanceid);
+ apparam.masinstanceid = 0;
- obc_transfer_set_apparam(transfer, apparam);
+ obc_transfer_set_apparam(transfer, &apparam);
if (obc_session_queue(mns->session, transfer, NULL, NULL, &err))
return dbus_message_new_method_return(message);
diff --git a/obexd/client/pbap.c b/obexd/client/pbap.c
index c803437d..c6313b14 100644
--- a/obexd/client/pbap.c
+++ b/obexd/client/pbap.c
@@ -367,7 +367,11 @@ static void read_return_apparam(struct obc_transfer *transfer,
g_obex_apparam_get_uint16(apparam, PHONEBOOKSIZE_TAG,
phone_book_size);
+#ifndef __TIZEN_PATCH__
+ g_obex_apparam_get_uint16(apparam, NEWMISSEDCALLS_TAG,
+#else
g_obex_apparam_get_uint8(apparam, NEWMISSEDCALLS_TAG,
+#endif
new_missed_calls);
read_version(pbap, apparam);
@@ -1094,9 +1098,9 @@ static const GDBusMethodTable pbap_methods[] = {
pbap_pull_vcard) },
{ GDBUS_ASYNC_METHOD("List",
#ifdef __TIZEN_PATCH__
- GDBUS_ARGS({ "folder", "s" }, {"filters", "a{sv}" }),
+ GDBUS_ARGS({ "folder", "s" }, {"filters", "a{sv}" }),
#else
- GDBUS_ARGS({"filters", "a{sv}" }),
+ GDBUS_ARGS({"filters", "a{sv}" }),
#endif
GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
pbap_list) },
diff --git a/obexd/client/session.c b/obexd/client/session.c
index 61b9357b..391d7130 100644
--- a/obexd/client/session.c
+++ b/obexd/client/session.c
@@ -65,6 +65,7 @@ static guint64 counter = 0;
struct callback_data {
struct obc_session *session;
+ guint id;
session_callback_t func;
void *data;
};
@@ -115,6 +116,7 @@ struct obc_session {
GQueue *queue;
guint process_id;
char *folder;
+ struct callback_data *callback;
};
static GSList *sessions = NULL;
@@ -306,6 +308,19 @@ disconnect:
session_free(session);
}
+static void callback_destroy(struct callback_data *callback, GError *err)
+{
+ struct obc_session *session = callback->session;
+
+ if (callback->id > 0)
+ g_obex_cancel_req(session->obex, callback->id, TRUE);
+
+ callback->func(session, NULL, err, callback->data);
+ g_free(callback);
+ session->callback = NULL;
+ obc_session_unref(session);
+}
+
static void connect_cb(GObex *obex, GError *err, GObexPacket *rsp,
gpointer user_data)
{
@@ -313,6 +328,8 @@ static void connect_cb(GObex *obex, GError *err, GObexPacket *rsp,
GError *gerr = NULL;
uint8_t rsp_code;
+ callback->id = 0;
+
if (err != NULL) {
error("connect_cb: %s", err->message);
gerr = g_error_copy(err);
@@ -325,11 +342,9 @@ static void connect_cb(GObex *obex, GError *err, GObexPacket *rsp,
"OBEX Connect failed with 0x%02x", rsp_code);
done:
- callback->func(callback->session, NULL, gerr, callback->data);
+ callback_destroy(callback, gerr);
if (gerr != NULL)
g_error_free(gerr);
- obc_session_unref(callback->session);
- g_free(callback);
}
static void session_disconnected(GObex *obex, GError *err, gpointer user_data)
@@ -389,24 +404,26 @@ static void transport_func(GIOChannel *io, GError *err, gpointer user_data)
len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
if (driver->target)
- g_obex_connect(obex, connect_cb, callback, &err,
+ callback->id = g_obex_connect(obex, connect_cb,
+ callback, &err,
G_OBEX_HDR_TARGET,
driver->target, driver->target_len,
G_OBEX_HDR_APPARAM,
buf, len,
G_OBEX_HDR_INVALID);
else
- g_obex_connect(obex, connect_cb, callback, &err,
+ callback->id = g_obex_connect(obex, connect_cb,
+ callback, &err,
G_OBEX_HDR_APPARAM, buf, len,
G_OBEX_HDR_INVALID);
g_obex_apparam_free(apparam);
} else if (driver->target)
- g_obex_connect(obex, connect_cb, callback, &err,
+ callback->id = g_obex_connect(obex, connect_cb, callback, &err,
G_OBEX_HDR_TARGET, driver->target, driver->target_len,
G_OBEX_HDR_INVALID);
else
- g_obex_connect(obex, connect_cb, callback, &err,
- G_OBEX_HDR_INVALID);
+ callback->id = g_obex_connect(obex, connect_cb, callback,
+ &err, G_OBEX_HDR_INVALID);
if (err != NULL) {
error("%s", err->message);
@@ -421,17 +438,28 @@ static void transport_func(GIOChannel *io, GError *err, gpointer user_data)
return;
done:
- callback->func(callback->session, NULL, err, callback->data);
- obc_session_unref(callback->session);
- g_free(callback);
+ callback_destroy(callback, err);
}
static void owner_disconnected(DBusConnection *connection, void *user_data)
{
struct obc_session *session = user_data;
+ GError *err;
DBG("");
+ /*
+ * If connection still connecting notify the callback to destroy the
+ * session.
+ */
+ if (session->callback) {
+ err = g_error_new(OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+ "Session closed by user");
+ callback_destroy(session->callback, err);
+ g_error_free(err);
+ return;
+ }
+
obc_session_shutdown(session);
}
@@ -537,6 +565,8 @@ static int session_connect(struct obc_session *session,
return -EINVAL;
}
+ session->callback = callback;
+
return 0;
}
@@ -1127,15 +1157,11 @@ static int session_process_setpath(struct pending_request *p, GError **err)
p->req_id = g_obex_setpath(p->session->obex, first, setpath_cb, p, err);
if (*err != NULL)
- goto fail;
+ return (*err)->code;
p->session->p = p;
return 0;
-
-fail:
- pending_request_free(p);
- return (*err)->code;
}
guint obc_session_setpath(struct obc_session *session, const char *path,
@@ -1159,6 +1185,9 @@ guint obc_session_setpath(struct obc_session *session, const char *path,
if (!data->remaining || !data->remaining[0]) {
error("obc_session_setpath: invalid path %s", path);
g_set_error(err, OBEX_IO_ERROR, -EINVAL, "Invalid argument");
+#ifdef __TIZEN_PATCH__
+ setpath_data_free(data);
+#endif
return 0;
}
@@ -1219,15 +1248,11 @@ static int session_process_mkdir(struct pending_request *p, GError **err)
p->req_id = g_obex_mkdir(p->session->obex, req->srcname, async_cb, p,
err);
if (*err != NULL)
- goto fail;
+ return (*err)->code;
p->session->p = p;
return 0;
-
-fail:
- pending_request_free(p);
- return (*err)->code;
}
guint obc_session_mkdir(struct obc_session *session, const char *folder,
@@ -1261,15 +1286,11 @@ static int session_process_copy(struct pending_request *p, GError **err)
p->req_id = g_obex_copy(p->session->obex, req->srcname, req->destname,
async_cb, p, err);
if (*err != NULL)
- goto fail;
+ return (*err)->code;
p->session->p = p;
return 0;
-
-fail:
- pending_request_free(p);
- return (*err)->code;
}
guint obc_session_copy(struct obc_session *session, const char *srcname,
@@ -1304,15 +1325,11 @@ static int session_process_move(struct pending_request *p, GError **err)
p->req_id = g_obex_move(p->session->obex, req->srcname, req->destname,
async_cb, p, err);
if (*err != NULL)
- goto fail;
+ return (*err)->code;
p->session->p = p;
return 0;
-
-fail:
- pending_request_free(p);
- return (*err)->code;
}
guint obc_session_move(struct obc_session *session, const char *srcname,
@@ -1347,15 +1364,11 @@ static int session_process_delete(struct pending_request *p, GError **err)
p->req_id = g_obex_delete(p->session->obex, req->srcname, async_cb, p,
err);
if (*err != NULL)
- goto fail;
+ return (*err)->code;
p->session->p = p;
return 0;
-
-fail:
- pending_request_free(p);
- return (*err)->code;
}
guint obc_session_delete(struct obc_session *session, const char *file,
diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c
index 5228ba82..5bb76677 100644
--- a/obexd/plugins/opp.c
+++ b/obexd/plugins/opp.c
@@ -42,7 +42,6 @@
#include "filesystem.h"
#define VCARD_TYPE "text/x-vcard"
-#define VCARD_FILE CONFIGDIR "/vcard.vcf"
static void *opp_connect(struct obex_session *os, int *err)
{
@@ -62,7 +61,6 @@ static void opp_progress(struct obex_session *os, void *user_data)
static int opp_chkput(struct obex_session *os, void *user_data)
{
char *folder, *name, *path;
- int32_t time;
const char *t;
int err;
@@ -79,8 +77,7 @@ static int opp_chkput(struct obex_session *os, void *user_data)
goto skip_auth;
}
- time = 0;
- err = manager_request_authorization(user_data, time, &folder, &name);
+ err = manager_request_authorization(user_data, &folder, &name);
if (err < 0)
return -EPERM;
@@ -134,6 +131,8 @@ static int opp_put(struct obex_session *os, void *user_data)
static int opp_get(struct obex_session *os, void *user_data)
{
const char *type;
+ char *folder, *path;
+ int err = 0;
if (obex_get_name(os))
return -EPERM;
@@ -143,14 +142,19 @@ static int opp_get(struct obex_session *os, void *user_data)
if (type == NULL)
return -EPERM;
+ folder = g_strdup(obex_option_root_folder());
+ path = g_build_filename(folder, "/vcard.vcf", NULL);
+
if (g_ascii_strcasecmp(type, VCARD_TYPE) == 0) {
- if (obex_get_stream_start(os, VCARD_FILE) < 0)
- return -ENOENT;
+ if (obex_get_stream_start(os, path) < 0)
+ err = -ENOENT;
} else
- return -EPERM;
+ err = -EPERM;
- return 0;
+ g_free(folder);
+ g_free(path);
+ return err;
}
static void opp_disconnect(struct obex_session *os, void *user_data)
diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
index 78926644..e21231c3 100644
--- a/obexd/plugins/pbap.c
+++ b/obexd/plugins/pbap.c
@@ -199,6 +199,8 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
phonebooksize);
+
+ pbap->obj->firstpacket = TRUE;
#ifndef __TIZEN_PATCH__
if (missed > 0) {
#else
@@ -206,7 +208,11 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
#endif /* __TIZEN_PATCH__ */
DBG("missed %d", missed);
+#ifndef __TIZEN_PATCH__
pbap->obj->apparam = g_obex_apparam_set_uint16(
+#else
+ pbap->obj->apparam = g_obex_apparam_set_uint8(
+#endif
pbap->obj->apparam,
NEWMISSEDCALLS_TAG,
missed);
@@ -248,7 +254,11 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
pbap->obj->firstpacket = TRUE;
+#ifndef __TIZEN_PATCH__
pbap->obj->apparam = g_obex_apparam_set_uint16(
+#else
+ pbap->obj->apparam = g_obex_apparam_set_uint8(
+#endif
pbap->obj->apparam,
NEWMISSEDCALLS_TAG,
missed);
@@ -387,7 +397,7 @@ static int generate_response(void *user_data)
#ifdef __TIZEN_PATCH__
if (pbap->params->required_missedcall_call_header == TRUE) {
//DBG("missed %d", missed);
- pbap->obj->apparam = g_obex_apparam_set_uint16(
+ pbap->obj->apparam = g_obex_apparam_set_uint8(
pbap->obj->apparam,
NEWMISSEDCALLS_TAG,
pbap->params->new_missed_calls);
@@ -399,7 +409,7 @@ static int generate_response(void *user_data)
#ifdef __TIZEN_PATCH__
if (pbap->params->required_missedcall_call_header == TRUE) {
pbap->obj->firstpacket = TRUE;
- pbap->obj->apparam = g_obex_apparam_set_uint16(
+ pbap->obj->apparam = g_obex_apparam_set_uint8(
pbap->obj->apparam,
NEWMISSEDCALLS_TAG,
pbap->params->new_missed_calls);
@@ -927,8 +937,6 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
ret = -ENOENT;
goto fail;
}
- DBG("pbap session: Folder[%s] Filter[%llu] Format[%d] ret[%d]",
- pbap->folder, pbap->params->filter, pbap->params->format, ret);
request = phonebook_get_entry(pbap->folder, id, pbap->params,
query_result, pbap, &ret);
@@ -940,14 +948,12 @@ done:
if (err)
*err = 0;
- DBG("-");
return vobject_create(pbap, request);
fail:
if (err)
*err = ret;
- DBG("-");
return NULL;
}
@@ -955,14 +961,13 @@ static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
uint8_t *hi)
{
struct pbap_object *obj = object;
- struct pbap_session *pbap = obj->session;
if (!obj->buffer && !obj->apparam)
return -EAGAIN;
*hi = G_OBEX_HDR_APPARAM;
- if (pbap->params->maxlistcount == 0 || obj->firstpacket) {
+ if (obj->firstpacket) {
obj->firstpacket = FALSE;
return g_obex_apparam_encode(obj->apparam, buf, mtu);
diff --git a/obexd/plugins/phonebook-dummy.c b/obexd/plugins/phonebook-dummy.c
index eeb078f2..199190eb 100644
--- a/obexd/plugins/phonebook-dummy.c
+++ b/obexd/plugins/phonebook-dummy.c
@@ -525,6 +525,11 @@ void *phonebook_get_entry(const char *folder, const char *id,
filename = g_build_filename(root_folder, folder, id, NULL);
fd = open(filename, O_RDONLY);
+
+#ifdef __TIZEN_PATCH__
+ g_free(filename);
+#endif
+
if (fd < 0) {
DBG("open(): %s(%d)", strerror(errno), errno);
if (err)
diff --git a/obexd/src/log.c b/obexd/src/log.c
index ace7ab64..f259728f 100644..100755
--- a/obexd/src/log.c
+++ b/obexd/src/log.c
@@ -125,7 +125,7 @@ void __obex_log_init(const char *debug, int detach)
openlog("obexd", option, LOG_DAEMON);
- syslog(LOG_INFO, "OBEX daemon %s", VERSION);
+ info("OBEX daemon %s", VERSION);
}
void __obex_log_cleanup(void)
diff --git a/obexd/src/log.h b/obexd/src/log.h
index d9fb8678..d9fb8678 100644..100755
--- a/obexd/src/log.h
+++ b/obexd/src/log.h
diff --git a/obexd/src/main.c b/obexd/src/main.c
index 515405c6..00644c94 100644..100755
--- a/obexd/src/main.c
+++ b/obexd/src/main.c
@@ -44,14 +44,12 @@
#include "gdbus/gdbus.h"
+#include "../client/manager.h"
+
#include "log.h"
#include "obexd.h"
#include "server.h"
-#ifdef __TIZEN_PATCH__
-#include "../client/manager.h"
-#endif
-
#define DEFAULT_CAP_FILE CONFIGDIR "/capability.xml"
static GMainLoop *main_loop = NULL;
diff --git a/obexd/src/manager.c b/obexd/src/manager.c
index ce20b019..9fbac6f6 100644..100755
--- a/obexd/src/manager.c
+++ b/obexd/src/manager.c
@@ -800,7 +800,7 @@ static gboolean auth_error(GIOChannel *io, GIOCondition cond, void *user_data)
return FALSE;
}
-int manager_request_authorization(struct obex_transfer *transfer, int32_t time,
+int manager_request_authorization(struct obex_transfer *transfer,
char **new_folder, char **new_name)
{
struct obex_session *os = transfer->session;
diff --git a/obexd/src/manager.h b/obexd/src/manager.h
index 669b223f..d9781b20 100644..100755
--- a/obexd/src/manager.h
+++ b/obexd/src/manager.h
@@ -36,7 +36,7 @@ void manager_unregister_transfer(struct obex_transfer *transfer);
void manager_emit_transfer_started(struct obex_transfer *transfer);
void manager_emit_transfer_progress(struct obex_transfer *transfer);
void manager_emit_transfer_completed(struct obex_transfer *transfer);
-int manager_request_authorization(struct obex_transfer *transfer, int32_t time,
+int manager_request_authorization(struct obex_transfer *transfer,
char **new_folder, char **new_name);
DBusConnection *manager_dbus_get_connection(void);
diff --git a/obexd/src/map_ap.h b/obexd/src/map_ap.h
index da108fe6..da108fe6 100644..100755
--- a/obexd/src/map_ap.h
+++ b/obexd/src/map_ap.h
diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c
index 833ddc72..833ddc72 100644..100755
--- a/obexd/src/mimetype.c
+++ b/obexd/src/mimetype.c
diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h
index 79529b89..79529b89 100644..100755
--- a/obexd/src/mimetype.h
+++ b/obexd/src/mimetype.h
diff --git a/obexd/src/obex-priv.h b/obexd/src/obex-priv.h
index 355a7f87..355a7f87 100644..100755
--- a/obexd/src/obex-priv.h
+++ b/obexd/src/obex-priv.h
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index 90832468..d62839f1 100644..100755
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
@@ -642,7 +642,17 @@ static void parse_name(struct obex_session *os, GObexPacket *req)
if (!g_obex_header_get_unicode(hdr, &name))
return;
-
+#ifdef __TIZEN_PATCH__
+ DBG("TYPE===>: %s", os->type);
+ if (name && strcmp(os->type, "x-bt/phonebook")) {
+ char *new_name;
+ new_name = strrchr(name, '/');
+ if (new_name) {
+ name = new_name + 1;
+ DBG("FileName %s", name);
+ }
+ }
+#endif
os->name = g_strdup(name);
DBG("NAME: %s", os->name);
}
diff --git a/obexd/src/obex.h b/obexd/src/obex.h
index fc167475..fc167475 100644..100755
--- a/obexd/src/obex.h
+++ b/obexd/src/obex.h
diff --git a/obexd/src/obex.service.in b/obexd/src/obex.service.in
index bca3aef6..bca3aef6 100644..100755
--- a/obexd/src/obex.service.in
+++ b/obexd/src/obex.service.in
diff --git a/obexd/src/obexd.h b/obexd/src/obexd.h
index 41f28d65..41f28d65 100644..100755
--- a/obexd/src/obexd.h
+++ b/obexd/src/obexd.h
diff --git a/obexd/src/org.bluez.obex.service b/obexd/src/org.bluez.obex.service
index b369d00b..b369d00b 100644..100755
--- a/obexd/src/org.bluez.obex.service
+++ b/obexd/src/org.bluez.obex.service
diff --git a/obexd/src/plugin.c b/obexd/src/plugin.c
index 7d971b6c..7d971b6c 100644..100755
--- a/obexd/src/plugin.c
+++ b/obexd/src/plugin.c
diff --git a/obexd/src/plugin.h b/obexd/src/plugin.h
index 13d77695..13d77695 100644..100755
--- a/obexd/src/plugin.h
+++ b/obexd/src/plugin.h
diff --git a/obexd/src/server.c b/obexd/src/server.c
index db854233..db854233 100644..100755
--- a/obexd/src/server.c
+++ b/obexd/src/server.c
diff --git a/obexd/src/server.h b/obexd/src/server.h
index 278c35fc..278c35fc 100644..100755
--- a/obexd/src/server.h
+++ b/obexd/src/server.h
diff --git a/obexd/src/service.c b/obexd/src/service.c
index c088535e..c088535e 100644..100755
--- a/obexd/src/service.c
+++ b/obexd/src/service.c
diff --git a/obexd/src/service.h b/obexd/src/service.h
index 5d9d325f..5d9d325f 100644..100755
--- a/obexd/src/service.h
+++ b/obexd/src/service.h
diff --git a/obexd/src/transport.c b/obexd/src/transport.c
index 4984643e..4984643e 100644..100755
--- a/obexd/src/transport.c
+++ b/obexd/src/transport.c
diff --git a/obexd/src/transport.h b/obexd/src/transport.h
index 97e10d05..97e10d05 100644..100755
--- a/obexd/src/transport.h
+++ b/obexd/src/transport.h
diff --git a/packaging/baselibs.conf b/packaging/baselibs.conf
index ec97a816..ec97a816 100755..100644
--- a/packaging/baselibs.conf
+++ b/packaging/baselibs.conf
diff --git a/packaging/bluetooth.modprobe b/packaging/bluetooth.modprobe
index 3072d788..3072d788 100755..100644
--- a/packaging/bluetooth.modprobe
+++ b/packaging/bluetooth.modprobe
diff --git a/packaging/bluetooth.sh b/packaging/bluetooth.sh
index 8cec6360..8cec6360 100755..100644
--- a/packaging/bluetooth.sh
+++ b/packaging/bluetooth.sh
diff --git a/packaging/bluetooth.sysconfig b/packaging/bluetooth.sysconfig
index d2bfec61..d2bfec61 100755..100644
--- a/packaging/bluetooth.sysconfig
+++ b/packaging/bluetooth.sysconfig
diff --git a/packaging/bluez-coldplug.init b/packaging/bluez-coldplug.init
index bf370b89..bf370b89 100755..100644
--- a/packaging/bluez-coldplug.init
+++ b/packaging/bluez-coldplug.init
diff --git a/packaging/bluez.changes b/packaging/bluez.changes
index 0f7fdf16..0f7fdf16 100755..100644
--- a/packaging/bluez.changes
+++ b/packaging/bluez.changes
diff --git a/packaging/bluez.manifest b/packaging/bluez.manifest
index 6c507893..6c507893 100755..100644
--- a/packaging/bluez.manifest
+++ b/packaging/bluez.manifest
diff --git a/packaging/bluez.spec b/packaging/bluez.spec
index f5c987b6..5d5e24ea 100644
--- a/packaging/bluez.spec
+++ b/packaging/bluez.spec
@@ -2,7 +2,7 @@
%define _libpath /usr/lib
Name: bluez
Summary: Bluetooth Stack for Linux
-Version: 5.28
+Version: 5.37
Release: 0
Group: Network & Connectivity/Bluetooth
License: GPL-2.0+ and LGPL-2.1+ and Apache-2.0
@@ -281,6 +281,7 @@ ln -sf bluetooth.service %{buildroot}%{_libpath}/systemd/system/dbus-org.bluez.s
%{_bindir}/bluemoon
%{_bindir}/gatttool
%{_bindir}/hex2hcd
+%{_bindir}/btattach
%exclude /usr/lib/debug/*
%docs_package
diff --git a/packaging/obex.sh b/packaging/obex.sh
index 884abde8..884abde8 100755..100644
--- a/packaging/obex.sh
+++ b/packaging/obex.sh
diff --git a/peripheral/attach.c b/peripheral/attach.c
new file mode 100644
index 00000000..a70ca55c
--- /dev/null
+++ b/peripheral/attach.c
@@ -0,0 +1,144 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "tools/hciattach.h"
+#include "peripheral/attach.h"
+
+static const char *serial_dev = "/dev/ttyS1";
+static int serial_fd = -1;
+
+static int open_serial(const char *path)
+{
+ struct termios ti;
+ int fd, saved_ldisc, ldisc = N_HCI;
+
+ fd = open(path, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ perror("Failed to open serial port");
+ return -1;
+ }
+
+ if (tcflush(fd, TCIOFLUSH) < 0) {
+ perror("Failed to flush serial port");
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, TIOCGETD, &saved_ldisc) < 0) {
+ perror("Failed get serial line discipline");
+ close(fd);
+ return -1;
+ }
+
+ /* Switch TTY to raw mode */
+ memset(&ti, 0, sizeof(ti));
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= (B115200 | CLOCAL | CREAD);
+
+ /* Set flow control */
+ ti.c_cflag |= CRTSCTS;
+
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Failed to set serial port settings");
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
+ perror("Failed set serial line discipline");
+ close(fd);
+ return -1;
+ }
+
+ printf("Switched line discipline from %d to %d\n", saved_ldisc, ldisc);
+
+ return fd;
+}
+
+static int attach_proto(const char *path, unsigned int proto,
+ unsigned int flags)
+{
+ int fd, dev_id;
+
+ fd = open_serial(path);
+ if (fd < 0)
+ return -1;
+
+ if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
+ perror("Failed to set flags");
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
+ perror("Failed to set protocol");
+ close(fd);
+ return -1;
+ }
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE);
+ if (dev_id < 0) {
+ perror("Failed to get device id");
+ close(fd);
+ return -1;
+ }
+
+ printf("Device index %d attached\n", dev_id);
+
+ return fd;
+}
+
+void attach_start(void)
+{
+ unsigned long flags;
+
+ if (serial_fd >= 0)
+ return;
+
+ printf("Attaching BR/EDR controller to %s\n", serial_dev);
+
+ flags = (1 << HCI_UART_RESET_ON_INIT);
+
+ serial_fd = attach_proto(serial_dev, HCI_UART_H4, flags);
+}
+
+void attach_stop(void)
+{
+ if (serial_fd < 0)
+ return;
+
+ close(serial_fd);
+ serial_fd = -1;
+}
diff --git a/peripheral/attach.h b/peripheral/attach.h
new file mode 100644
index 00000000..f76e2fba
--- /dev/null
+++ b/peripheral/attach.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void attach_start(void);
+void attach_stop(void);
diff --git a/peripheral/efivars.c b/peripheral/efivars.c
new file mode 100644
index 00000000..a86031fb
--- /dev/null
+++ b/peripheral/efivars.c
@@ -0,0 +1,132 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include "peripheral/efivars.h"
+
+#define SYSFS_EFIVARS "/sys/firmware/efi/efivars"
+
+typedef struct {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+} efi_guid_t;
+
+#define VENDOR_GUID \
+ (efi_guid_t) { 0xd5f9d775, 0x1a09, 0x4e89, \
+ { 0x96, 0xcf, 0x1d, 0x19, 0x55, 0x4d, 0xa6, 0x67 } }
+
+static void efivars_pathname(const char *name, char *pathname, size_t size)
+{
+ static efi_guid_t guid = VENDOR_GUID;
+
+ snprintf(pathname, size - 1,
+ "%s/%s-%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ SYSFS_EFIVARS, name, guid.data1, guid.data2, guid.data3,
+ guid.data4[0], guid.data4[1], guid.data4[2], guid.data4[3],
+ guid.data4[4], guid.data4[5], guid.data4[6], guid.data4[7]);
+}
+
+int efivars_read(const char *name, uint32_t *attributes,
+ void *data, size_t size)
+{
+ char pathname[PATH_MAX];
+ struct iovec iov[2];
+ uint32_t attr;
+ ssize_t len;
+ int fd;
+
+ efivars_pathname(name, pathname, PATH_MAX);
+
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ return -EIO;
+
+ iov[0].iov_base = &attr;
+ iov[0].iov_len = sizeof(attr);
+ iov[1].iov_base = data;
+ iov[1].iov_len = size;
+
+ len = readv(fd, iov, 2);
+
+ close(fd);
+
+ if (len < 0)
+ return -EIO;
+
+ if (attributes)
+ *attributes = attr;
+
+ return 0;
+}
+
+int efivars_write(const char *name, uint32_t attributes,
+ const void *data, size_t size)
+{
+ char pathname[PATH_MAX];
+ void *buf;
+ ssize_t written;
+ int fd;
+
+ efivars_pathname(name, pathname, PATH_MAX);
+
+ buf = malloc(size + sizeof(attributes));
+ if (!buf)
+ return -ENOMEM;
+
+ fd = open(pathname, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ free(buf);
+ return -EIO;
+ }
+
+ memcpy(buf, &attributes, sizeof(attributes));
+ memcpy(buf + sizeof(attributes), data, size);
+
+ written = write(fd, buf, size + sizeof(attributes));
+
+ close(fd);
+ free(buf);
+
+ if (written < 0)
+ return -EIO;
+
+ return 0;
+}
diff --git a/peripheral/efivars.h b/peripheral/efivars.h
new file mode 100644
index 00000000..430d1433
--- /dev/null
+++ b/peripheral/efivars.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define EFIVARS_NON_VOLATILE 0x00000001
+#define EFIVARS_BOOTSERVICE_ACCESS 0x00000002
+#define EFIVARS_RUNTIME_ACCESS 0x00000004
+#define EFIVARS_HARDWARE_ERROR_RECORD 0x00000008
+#define EFIVARS_AUTHENTICATED_WRITE_ACCESS 0x00000010
+
+int efivars_read(const char *name, uint32_t *attributes,
+ void *data, size_t size);
+int efivars_write(const char *name, uint32_t attributes,
+ const void *data, size_t size);
diff --git a/peripheral/gap.c b/peripheral/gap.c
new file mode 100644
index 00000000..f659f7fe
--- /dev/null
+++ b/peripheral/gap.c
@@ -0,0 +1,551 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+#include "src/shared/util.h"
+#include "src/shared/mgmt.h"
+#include "peripheral/gatt.h"
+#include "peripheral/gap.h"
+
+static struct mgmt *mgmt = NULL;
+static uint16_t mgmt_index = MGMT_INDEX_NONE;
+
+static bool adv_features = false;
+static bool adv_instances = false;
+static bool require_connectable = true;
+
+static uint8_t static_addr[6] = { 0x90, 0x78, 0x56, 0x34, 0x12, 0xc0 };
+static uint8_t dev_name[260] = { 0x00, };
+static uint8_t dev_name_len = 0;
+
+void gap_set_static_address(uint8_t addr[6])
+{
+ memcpy(static_addr, addr, sizeof(static_addr));
+
+ printf("Using static address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ static_addr[5], static_addr[4], static_addr[3],
+ static_addr[2], static_addr[1], static_addr[0]);
+}
+
+static void clear_long_term_keys(uint16_t index)
+{
+ struct mgmt_cp_load_long_term_keys cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.key_count = cpu_to_le16(0);
+
+ mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index,
+ sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void clear_identity_resolving_keys(uint16_t index)
+{
+ struct mgmt_cp_load_irks cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.irk_count = cpu_to_le16(0);
+
+ mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index,
+ sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void add_advertising(uint16_t index)
+{
+ const char ad[] = { 0x11, 0x15,
+ 0xd0, 0x00, 0x2d, 0x12, 0x1e, 0x4b, 0x0f, 0xa4,
+ 0x99, 0x4e, 0xce, 0xb5, 0x31, 0xf4, 0x05, 0x79 };
+ struct mgmt_cp_add_advertising *cp;
+ void *buf;
+
+ buf = malloc(sizeof(*cp) + sizeof(ad));
+ if (!buf)
+ return;
+
+ memset(buf, 0, sizeof(*cp) + sizeof(ad));
+ cp = buf;
+ cp->instance = 0x01;
+ cp->flags = cpu_to_le32((1 << 0) | (1 << 1) | (1 << 4));
+ cp->duration = cpu_to_le16(0);
+ cp->timeout = cpu_to_le16(0);
+ cp->adv_data_len = sizeof(ad);
+ cp->scan_rsp_len = 0;
+ memcpy(cp->data, ad, sizeof(ad));
+
+ mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index,
+ sizeof(*cp) + sizeof(ad), buf, NULL, NULL, NULL);
+
+ free(buf);
+}
+
+static void enable_advertising(uint16_t index)
+{
+ uint8_t val;
+
+ val = require_connectable ? 0x01 : 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_CONNECTABLE, index, 1, &val,
+ NULL, NULL, NULL);
+
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
+ NULL, NULL, NULL);
+
+ if (adv_instances) {
+ add_advertising(index);
+ return;
+ }
+
+ val = require_connectable ? 0x01 : 0x02;
+ mgmt_send(mgmt, MGMT_OP_SET_ADVERTISING, index, 1, &val,
+ NULL, NULL, NULL);
+}
+
+static void new_settings_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("New settings\n");
+}
+
+static void local_name_changed_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Local name changed\n");
+}
+
+static void new_long_term_key_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("New long term key\n");
+}
+
+static void device_connected_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Device connected\n");
+}
+
+static void device_disconnected_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Device disconnected\n");
+}
+
+static void user_confirm_request_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("User confirm request\n");
+}
+
+static void user_passkey_request_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("User passkey request\n");
+}
+
+static void auth_failed_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Authentication failed\n");
+}
+
+static void device_unpaired_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Device unpaired\n");
+}
+
+static void passkey_notify_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Passkey notification\n");
+}
+
+static void new_irk_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("New identify resolving key\n");
+}
+
+static void new_csrk_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("New connection signature resolving key\n");
+}
+
+static void new_conn_param_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("New connection parameter\n");
+}
+
+static void advertising_added_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Advertising added\n");
+}
+
+static void advertising_removed_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Advertising removed\n");
+}
+
+static void read_adv_features_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_adv_features *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ uint32_t flags;
+
+ flags = le32_to_cpu(rp->supported_flags);
+
+ if (rp->max_instances > 0) {
+ adv_instances = true;
+
+ if (flags & (1 << 0))
+ require_connectable = false;
+ } else
+ require_connectable = false;
+
+ enable_advertising(index);
+}
+
+static void read_info_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_info *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ uint32_t required_settings = MGMT_SETTING_LE |
+ MGMT_SETTING_STATIC_ADDRESS;
+ uint32_t supported_settings, current_settings;
+ uint8_t val;
+
+ required_settings = MGMT_SETTING_LE;
+
+ if (status) {
+ fprintf(stderr, "Reading info for index %u failed: %s\n",
+ index, mgmt_errstr(status));
+ return;
+ }
+
+ if (mgmt_index != MGMT_INDEX_NONE)
+ return;
+
+ supported_settings = le32_to_cpu(rp->supported_settings);
+ current_settings = le32_to_cpu(rp->current_settings);
+
+ if ((supported_settings & required_settings) != required_settings)
+ return;
+
+ printf("Selecting index %u\n", index);
+ mgmt_index = index;
+
+ mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index,
+ new_settings_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
+ local_name_changed_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_LONG_TERM_KEY, index,
+ new_long_term_key_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index,
+ device_connected_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index,
+ device_disconnected_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index,
+ user_confirm_request_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
+ user_passkey_request_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index,
+ auth_failed_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DEVICE_UNPAIRED, index,
+ device_unpaired_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
+ passkey_notify_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_IRK, index,
+ new_irk_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_CSRK, index,
+ new_csrk_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_CONN_PARAM, index,
+ new_conn_param_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index,
+ advertising_added_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index,
+ advertising_removed_event, NULL, NULL);
+
+ dev_name_len = snprintf((char *) dev_name, 26, "BlueZ Peripheral");
+
+ if (current_settings & MGMT_SETTING_POWERED) {
+ val = 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ if (!(current_settings & MGMT_SETTING_LE)) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ if (current_settings & MGMT_SETTING_BREDR) {
+ val = 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ if ((supported_settings & MGMT_SETTING_SECURE_CONN) &&
+ !(current_settings & MGMT_SETTING_SECURE_CONN)) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ if (current_settings & MGMT_SETTING_DEBUG_KEYS) {
+ val = 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ if (!(current_settings & MGMT_SETTING_BONDABLE)) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ clear_long_term_keys(mgmt_index);
+ clear_identity_resolving_keys(mgmt_index);
+
+ mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
+ 6, static_addr, NULL, NULL, NULL);
+
+ mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index,
+ 260, dev_name, NULL, NULL, NULL);
+
+ gatt_set_static_address(static_addr);
+ gatt_set_device_name(dev_name, dev_name_len);
+ gatt_server_start();
+
+ if (adv_features)
+ mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL,
+ read_adv_features_complete,
+ UINT_TO_PTR(index), NULL);
+ else
+ enable_advertising(index);
+}
+
+static void read_index_list_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_index_list *rp = param;
+ uint16_t count;
+ int i;
+
+ if (status) {
+ fprintf(stderr, "Reading index list failed: %s\n",
+ mgmt_errstr(status));
+ return;
+ }
+
+ count = le16_to_cpu(rp->num_controllers);
+
+ printf("Index list: %u\n", count);
+
+ for (i = 0; i < count; i++) {
+ uint16_t index = cpu_to_le16(rp->index[i]);
+
+ mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+ read_info_complete, UINT_TO_PTR(index), NULL);
+ }
+}
+
+static void index_added_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Index added\n");
+
+ if (mgmt_index != MGMT_INDEX_NONE)
+ return;
+
+ mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+ read_info_complete, UINT_TO_PTR(index), NULL);
+}
+
+static void index_removed_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ printf("Index removed\n");
+
+ if (mgmt_index != index)
+ return;
+
+ mgmt_index = MGMT_INDEX_NONE;
+}
+
+static void read_ext_index_list_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_ext_index_list *rp = param;
+ uint16_t count;
+ int i;
+
+ if (status) {
+ fprintf(stderr, "Reading extended index list failed: %s\n",
+ mgmt_errstr(status));
+ return;
+ }
+
+ count = le16_to_cpu(rp->num_controllers);
+
+ printf("Extended index list: %u\n", count);
+
+ for (i = 0; i < count; i++) {
+ uint16_t index = cpu_to_le16(rp->entry[i].index);
+
+ if (rp->entry[i].type != 0x00)
+ continue;
+
+ mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+ read_info_complete, UINT_TO_PTR(index), NULL);
+ }
+}
+
+static void ext_index_added_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_ext_index_added *ev = param;
+
+ printf("Extended index added: %u\n", ev->type);
+
+ if (mgmt_index != MGMT_INDEX_NONE)
+ return;
+
+ if (ev->type != 0x00)
+ return;
+
+ mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+ read_info_complete, UINT_TO_PTR(index), NULL);
+}
+
+static void ext_index_removed_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_ext_index_added *ev = param;
+
+ printf("Extended index removed: %u\n", ev->type);
+
+ if (mgmt_index != index)
+ return;
+
+ if (ev->type != 0x00)
+ return;
+
+ mgmt_index = MGMT_INDEX_NONE;
+}
+
+static void read_commands_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_commands *rp = param;
+ const uint16_t *opcode;
+ uint16_t num_commands;
+ bool ext_index_list = false;
+ int i;
+
+ if (status) {
+ fprintf(stderr, "Reading index list failed: %s\n",
+ mgmt_errstr(status));
+ return;
+ }
+
+ num_commands = le16_to_cpu(rp->num_commands);
+ opcode = rp->opcodes;
+
+ for (i = 0; i < num_commands; i++) {
+ uint16_t op = get_le16(opcode++);
+
+ if (op == MGMT_OP_READ_EXT_INDEX_LIST)
+ ext_index_list = true;
+ else if (op == MGMT_OP_READ_ADV_FEATURES)
+ adv_features = true;
+ }
+
+ if (ext_index_list) {
+ mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, MGMT_INDEX_NONE,
+ ext_index_added_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, MGMT_INDEX_NONE,
+ ext_index_removed_event, NULL, NULL);
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST,
+ MGMT_INDEX_NONE, 0, NULL,
+ read_ext_index_list_complete, NULL, NULL)) {
+ fprintf(stderr, "Failed to read extended index list\n");
+ return;
+ }
+ } else {
+ mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+ index_added_event, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+ index_removed_event, NULL, NULL);
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
+ MGMT_INDEX_NONE, 0, NULL,
+ read_index_list_complete, NULL, NULL)) {
+ fprintf(stderr, "Failed to read index list\n");
+ return;
+ }
+ }
+}
+
+void gap_start(void)
+{
+ mgmt = mgmt_new_default();
+ if (!mgmt) {
+ fprintf(stderr, "Failed to open management socket\n");
+ return;
+ }
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_COMMANDS,
+ MGMT_INDEX_NONE, 0, NULL,
+ read_commands_complete, NULL, NULL)) {
+ fprintf(stderr, "Failed to read supported commands\n");
+ return;
+ }
+}
+
+void gap_stop(void)
+{
+ if (!mgmt)
+ return;
+
+ gatt_server_stop();
+
+ mgmt_unref(mgmt);
+ mgmt = NULL;
+
+ mgmt_index = MGMT_INDEX_NONE;
+}
diff --git a/peripheral/gap.h b/peripheral/gap.h
new file mode 100644
index 00000000..6d673781
--- /dev/null
+++ b/peripheral/gap.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+void gap_set_static_address(uint8_t addr[6]);
+
+void gap_start(void);
+void gap_stop(void);
diff --git a/peripheral/gatt.c b/peripheral/gatt.c
new file mode 100644
index 00000000..4c5531d8
--- /dev/null
+++ b/peripheral/gatt.c
@@ -0,0 +1,318 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/uuid.h"
+#include "src/shared/mainloop.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/gatt-client.h"
+#include "peripheral/gatt.h"
+
+#define ATT_CID 4
+
+#define UUID_GAP 0x1800
+
+struct gatt_conn {
+ struct bt_att *att;
+ struct bt_gatt_server *gatt;
+ struct bt_gatt_client *client;
+};
+
+static int att_fd = -1;
+static struct queue *conn_list = NULL;
+static struct gatt_db *gatt_db = NULL;
+static struct gatt_db *gatt_cache = NULL;
+
+static uint8_t static_addr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static uint8_t dev_name[20];
+static uint8_t dev_name_len = 0;
+
+void gatt_set_static_address(uint8_t addr[6])
+{
+ memcpy(static_addr, addr, sizeof(static_addr));
+}
+
+void gatt_set_device_name(uint8_t name[20], uint8_t len)
+{
+ memcpy(dev_name, name, sizeof(dev_name));
+ dev_name_len = len;
+}
+
+static void gatt_conn_destroy(void *data)
+{
+ struct gatt_conn *conn = data;
+
+ bt_gatt_client_unref(conn->client);
+ bt_gatt_server_unref(conn->gatt);
+ bt_att_unref(conn->att);
+
+ free(conn);
+}
+
+static void gatt_conn_disconnect(int err, void *user_data)
+{
+ struct gatt_conn *conn = user_data;
+
+ printf("Device disconnected: %s\n", strerror(err));
+
+ queue_remove(conn_list, conn);
+ gatt_conn_destroy(conn);
+}
+
+static void client_ready_callback(bool success, uint8_t att_ecode,
+ void *user_data)
+{
+ printf("GATT client discovery complete\n");
+}
+
+static void client_service_changed_callback(uint16_t start_handle,
+ uint16_t end_handle,
+ void *user_data)
+{
+ printf("GATT client service changed notification\n");
+}
+
+static struct gatt_conn *gatt_conn_new(int fd)
+{
+ struct gatt_conn *conn;
+ uint16_t mtu = 0;
+
+ conn = new0(struct gatt_conn, 1);
+ if (!conn)
+ return NULL;
+
+ conn->att = bt_att_new(fd, false);
+ if (!conn->att) {
+ fprintf(stderr, "Failed to initialze ATT transport layer\n");
+ free(conn);
+ return NULL;
+ }
+
+ bt_att_set_close_on_unref(conn->att, true);
+ bt_att_register_disconnect(conn->att, gatt_conn_disconnect, conn, NULL);
+
+ bt_att_set_security(conn->att, BT_SECURITY_MEDIUM);
+
+ conn->gatt = bt_gatt_server_new(gatt_db, conn->att, mtu);
+ if (!conn->gatt) {
+ fprintf(stderr, "Failed to create GATT server\n");
+ bt_att_unref(conn->att);
+ free(conn);
+ return NULL;
+ }
+
+ conn->client = bt_gatt_client_new(gatt_cache, conn->att, mtu);
+ if (!conn->gatt) {
+ fprintf(stderr, "Failed to create GATT client\n");
+ bt_gatt_server_unref(conn->gatt);
+ bt_att_unref(conn->att);
+ free(conn);
+ return NULL;
+ }
+
+ bt_gatt_client_set_ready_handler(conn->client,
+ client_ready_callback, conn, NULL);
+ bt_gatt_client_set_service_changed(conn->client,
+ client_service_changed_callback, conn, NULL);
+
+ return conn;
+}
+
+static void att_conn_callback(int fd, uint32_t events, void *user_data)
+{
+ struct gatt_conn *conn;
+ struct sockaddr_l2 addr;
+ socklen_t addrlen;
+ int new_fd;
+
+ if (events & (EPOLLERR | EPOLLHUP)) {
+ mainloop_remove_fd(fd);
+ return;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ new_fd = accept(att_fd, (struct sockaddr *) &addr, &addrlen);
+ if (new_fd < 0) {
+ fprintf(stderr, "Failed to accept new ATT connection: %m\n");
+ return;
+ }
+
+ conn = gatt_conn_new(new_fd);
+ if (!conn) {
+ fprintf(stderr, "Failed to create GATT connection\n");
+ close(new_fd);
+ return;
+ }
+
+ if (!queue_push_tail(conn_list, conn)) {
+ fprintf(stderr, "Failed to add GATT connection\n");
+ gatt_conn_destroy(conn);
+ close(new_fd);
+ }
+
+ printf("New device connected\n");
+}
+
+static void gap_device_name_read(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ uint8_t error;
+ const uint8_t *value;
+ size_t len;
+
+ if (offset > dev_name_len) {
+ error = BT_ATT_ERROR_INVALID_OFFSET;
+ value = NULL;
+ len = dev_name_len;
+ } else {
+ error = 0;
+ len = dev_name_len - offset;
+ value = len ? &dev_name[offset] : NULL;
+ }
+
+ gatt_db_attribute_read_result(attrib, id, error, value, len);
+}
+
+static void populate_gap_service(struct gatt_db *db)
+{
+ struct gatt_db_attribute *service;
+ bt_uuid_t uuid;
+
+ bt_uuid16_create(&uuid, UUID_GAP);
+ service = gatt_db_add_service(db, &uuid, true, 6);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
+ gatt_db_service_add_characteristic(service, &uuid,
+ BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ,
+ gap_device_name_read, NULL, NULL);
+
+ gatt_db_service_set_active(service, true);
+}
+
+static void populate_devinfo_service(struct gatt_db *db)
+{
+ struct gatt_db_attribute *service;
+ bt_uuid_t uuid;
+
+ bt_uuid16_create(&uuid, 0x180a);
+ service = gatt_db_add_service(db, &uuid, true, 17);
+
+ gatt_db_service_set_active(service, true);
+}
+
+void gatt_server_start(void)
+{
+ struct sockaddr_l2 addr;
+
+ if (att_fd >= 0)
+ return;
+
+ att_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_CLOEXEC,
+ BTPROTO_L2CAP);
+ if (att_fd < 0) {
+ fprintf(stderr, "Failed to create ATT server socket: %m\n");
+ return;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ addr.l2_cid = htobs(ATT_CID);
+ memcpy(&addr.l2_bdaddr, static_addr, 6);
+ addr.l2_bdaddr_type = BDADDR_LE_RANDOM;
+
+ if (bind(att_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "Failed to bind ATT server socket: %m\n");
+ close(att_fd);
+ att_fd = -1;
+ return;
+ }
+
+ if (listen(att_fd, 1) < 0) {
+ fprintf(stderr, "Failed to listen on ATT server socket: %m\n");
+ close(att_fd);
+ att_fd = -1;
+ return;
+ }
+
+ gatt_db = gatt_db_new();
+ if (!gatt_db) {
+ close(att_fd);
+ att_fd = -1;
+ return;
+ }
+
+ populate_gap_service(gatt_db);
+ populate_devinfo_service(gatt_db);
+
+ gatt_cache = gatt_db_new();
+
+ conn_list = queue_new();
+ if (!conn_list) {
+ gatt_db_unref(gatt_db);
+ gatt_db = NULL;
+ close(att_fd);
+ att_fd = -1;
+ return;
+ }
+
+ mainloop_add_fd(att_fd, EPOLLIN, att_conn_callback, NULL, NULL);
+}
+
+void gatt_server_stop(void)
+{
+ if (att_fd < 0)
+ return;
+
+ mainloop_remove_fd(att_fd);
+
+ queue_destroy(conn_list, gatt_conn_destroy);
+
+ gatt_db_unref(gatt_cache);
+ gatt_cache = NULL;
+
+ gatt_db_unref(gatt_db);
+ gatt_db = NULL;
+
+ close(att_fd);
+ att_fd = -1;
+}
diff --git a/peripheral/gatt.h b/peripheral/gatt.h
new file mode 100644
index 00000000..5b68f357
--- /dev/null
+++ b/peripheral/gatt.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+void gatt_set_static_address(uint8_t addr[6]);
+void gatt_set_device_name(uint8_t name[20], uint8_t len);
+
+void gatt_server_start(void);
+void gatt_server_stop(void);
diff --git a/peripheral/log.c b/peripheral/log.c
new file mode 100644
index 00000000..7aaeb4d8
--- /dev/null
+++ b/peripheral/log.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "peripheral/log.h"
+
+static int kmsg_fd = -1;
+
+void log_open(void)
+{
+ if (kmsg_fd >= 0)
+ return;
+
+ kmsg_fd = open("/dev/kmsg", O_WRONLY | O_NOCTTY | O_CLOEXEC);
+ if (kmsg_fd < 0) {
+ fprintf(stderr, "Failed to open kernel logging: %m\n");
+ return;
+ }
+}
+
+void log_close(void)
+{
+ if (kmsg_fd < 0)
+ return;
+
+ close(kmsg_fd);
+ kmsg_fd = -1;
+}
diff --git a/peripheral/log.h b/peripheral/log.h
new file mode 100644
index 00000000..36619b36
--- /dev/null
+++ b/peripheral/log.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void log_open(void);
+void log_close(void);
diff --git a/peripheral/main.c b/peripheral/main.c
new file mode 100644
index 00000000..d7e10f3d
--- /dev/null
+++ b/peripheral/main.c
@@ -0,0 +1,247 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+
+#ifndef WAIT_ANY
+#define WAIT_ANY (-1)
+#endif
+
+#include "src/shared/mainloop.h"
+#include "peripheral/efivars.h"
+#include "peripheral/attach.h"
+#include "peripheral/gap.h"
+#include "peripheral/log.h"
+
+static bool is_init = false;
+static pid_t shell_pid = -1;
+
+static const struct {
+ const char *target;
+ const char *linkpath;
+} dev_table[] = {
+ { "/proc/self/fd", "/dev/fd" },
+ { "/proc/self/fd/0", "/dev/stdin" },
+ { "/proc/self/fd/1", "/dev/stdout" },
+ { "/proc/self/fd/2", "/dev/stderr" },
+ { }
+};
+
+static const struct {
+ const char *fstype;
+ const char *target;
+ const char *options;
+ unsigned long flags;
+} mount_table[] = {
+ { "sysfs", "/sys", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
+ { "proc", "/proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
+ { "devtmpfs", "/dev", NULL, MS_NOSUID|MS_STRICTATIME },
+ { "efivarfs", "/sys/firmware/efi/efivars",
+ NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
+ { "pstore", "/sys/fs/pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
+ { }
+};
+
+static void prepare_filesystem(void)
+{
+ int i;
+
+ if (!is_init)
+ return;
+
+ for (i = 0; mount_table[i].fstype; i++) {
+ struct stat st;
+
+ if (lstat(mount_table[i].target, &st) < 0) {
+ printf("Creating %s\n", mount_table[i].target);
+ mkdir(mount_table[i].target, 0755);
+ }
+
+ printf("Mounting %s to %s\n", mount_table[i].fstype,
+ mount_table[i].target);
+
+ if (mount(mount_table[i].fstype,
+ mount_table[i].target,
+ mount_table[i].fstype,
+ mount_table[i].flags, NULL) < 0)
+ perror("Failed to mount filesystem");
+ }
+
+ for (i = 0; dev_table[i].target; i++) {
+ printf("Linking %s to %s\n", dev_table[i].linkpath,
+ dev_table[i].target);
+
+ if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
+ perror("Failed to create device symlink");
+ }
+}
+
+static void run_shell(void)
+{
+ pid_t pid;
+
+ printf("Starting shell\n");
+
+ pid = fork();
+ if (pid < 0) {
+ perror("Failed to fork new process");
+ return;
+ }
+
+ if (pid == 0) {
+ char *prg_argv[] = { "/bin/sh", NULL };
+ char *prg_envp[] = { NULL };
+
+ execve(prg_argv[0], prg_argv, prg_envp);
+ exit(0);
+ }
+
+ printf("PID %d created\n", pid);
+
+ shell_pid = pid;
+}
+
+static void exit_shell(void)
+{
+ shell_pid = -1;
+
+ if (!is_init) {
+ mainloop_quit();
+ return;
+ }
+
+ run_shell();
+}
+
+static void signal_callback(int signum, void *user_data)
+{
+ switch (signum) {
+ case SIGINT:
+ case SIGTERM:
+ mainloop_quit();
+ break;
+ case SIGCHLD:
+ while (1) {
+ pid_t pid;
+ int status;
+
+ pid = waitpid(WAIT_ANY, &status, WNOHANG);
+ if (pid < 0 || pid == 0)
+ break;
+
+ if (WIFEXITED(status)) {
+ printf("PID %d exited (status=%d)\n",
+ pid, WEXITSTATUS(status));
+
+ if (pid == shell_pid)
+ exit_shell();
+ } else if (WIFSIGNALED(status)) {
+ printf("PID %d terminated (signal=%d)\n",
+ pid, WTERMSIG(status));
+
+ if (pid == shell_pid)
+ exit_shell();
+ }
+ }
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ sigset_t mask;
+ int exit_status;
+
+ if (getpid() == 1 && getppid() == 0)
+ is_init = true;
+
+ mainloop_init();
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGCHLD);
+
+ mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+ printf("Bluetooth periperhal ver %s\n", VERSION);
+
+ prepare_filesystem();
+
+ if (is_init) {
+ uint8_t addr[6];
+
+ if (efivars_read("BluetoothStaticAddress", NULL,
+ addr, 6) < 0) {
+ printf("Generating new persistent static address\n");
+
+ addr[0] = rand();
+ addr[1] = rand();
+ addr[2] = rand();
+ addr[3] = 0x34;
+ addr[4] = 0x12;
+ addr[5] = 0xc0;
+
+ efivars_write("BluetoothStaticAddress",
+ EFIVARS_NON_VOLATILE |
+ EFIVARS_BOOTSERVICE_ACCESS |
+ EFIVARS_RUNTIME_ACCESS,
+ addr, 6);
+ }
+
+ gap_set_static_address(addr);
+
+ run_shell();
+ }
+
+ log_open();
+ gap_start();
+
+ if (is_init)
+ attach_start();
+
+ exit_status = mainloop_run();
+
+ if (is_init)
+ attach_stop();
+
+ gap_stop();
+ log_close();
+
+ return exit_status;
+}
diff --git a/plugins/policy.c b/plugins/policy.c
index 978a2d60..0f0da33a 100644
--- a/plugins/policy.c
+++ b/plugins/policy.c
@@ -55,34 +55,42 @@
#define SINK_RETRY_TIMEOUT SOURCE_RETRY_TIMEOUT
#define CT_RETRY_TIMEOUT 1
#define TG_RETRY_TIMEOUT CT_RETRY_TIMEOUT
+#ifdef __TIZEN_PATCH__
+#define SOURCE_RETRIES 0
+#else
#define SOURCE_RETRIES 1
+#endif
#define SINK_RETRIES SOURCE_RETRIES
#define CT_RETRIES 1
#define TG_RETRIES CT_RETRIES
-/* Tracking of remote services to be auto-reconnected upon link loss */
-
-#define RECONNECT_GIVE_UP (3 * 60)
-#define RECONNECT_TIMEOUT 1
-
struct reconnect_data {
struct btd_device *dev;
bool reconnect;
GSList *services;
guint timer;
bool active;
- time_t start;
- int timeout;
+ unsigned int attempt;
};
static const char *default_reconnect[] = {
HSP_AG_UUID, HFP_AG_UUID, A2DP_SOURCE_UUID, NULL };
static char **reconnect_uuids = NULL;
+
+static const size_t default_attempts = 7;
+static size_t reconnect_attempts = 0;
+
+static const int default_intervals[] = { 1, 2, 4, 8, 16, 32, 64 };
+static int *reconnect_intervals = NULL;
+static size_t reconnect_intervals_len = 0;
+
static GSList *reconnects = NULL;
static unsigned int service_id = 0;
static GSList *devices = NULL;
+static bool auto_enable = false;
+
struct policy_data {
struct btd_device *dev;
@@ -383,9 +391,13 @@ static void source_cb(struct btd_service *service,
if (data->tg_timer > 0) {
g_source_remove(data->tg_timer);
data->tg_timer = 0;
+#if defined __TIZEN_PATCH__ && defined BT_QUALIFICATION
+ }
+#else
} else if (btd_service_get_state(target) !=
BTD_SERVICE_STATE_DISCONNECTED)
policy_disconnect(data, target);
+#endif
break;
case BTD_SERVICE_STATE_CONNECTING:
break;
@@ -511,8 +523,7 @@ static void target_cb(struct btd_service *service,
static void reconnect_reset(struct reconnect_data *reconnect)
{
- reconnect->start = 0;
- reconnect->timeout = 1;
+ reconnect->attempt = 0;
if (reconnect->timer > 0) {
g_source_remove(reconnect->timer);
@@ -684,9 +695,6 @@ static gboolean reconnect_timeout(gpointer data)
/* Mark the GSource as invalid */
reconnect->timer = 0;
- /* Increase timeout for the next attempt if this * one fails. */
- reconnect->timeout *= 2;
-
err = btd_device_connect_services(reconnect->dev, reconnect->services);
if (err < 0) {
error("Reconnecting services failed: %s (%d)",
@@ -696,13 +704,26 @@ static gboolean reconnect_timeout(gpointer data)
}
reconnect->active = true;
-
- if (!reconnect->start)
- reconnect->start = time(NULL);
+ reconnect->attempt++;
return FALSE;
}
+static void reconnect_set_timer(struct reconnect_data *reconnect)
+{
+ static int timeout = 0;
+
+ reconnect->attempt++;
+
+ if (reconnect->attempt < reconnect_intervals_len)
+ timeout = reconnect_intervals[reconnect->attempt];
+
+ DBG("%d seconds", timeout);
+
+ reconnect->timer = g_timeout_add_seconds(timeout, reconnect_timeout,
+ reconnect);
+}
+
static void disconnect_cb(struct btd_device *dev, uint8_t reason)
{
struct reconnect_data *reconnect;
@@ -719,15 +740,12 @@ static void disconnect_cb(struct btd_device *dev, uint8_t reason)
DBG("Device %s identified for auto-reconnection",
device_get_path(dev));
- reconnect->timer = g_timeout_add_seconds(reconnect->timeout,
- reconnect_timeout,
- reconnect);
+ reconnect_set_timer(reconnect);
}
static void conn_fail_cb(struct btd_device *dev, uint8_t status)
{
struct reconnect_data *reconnect;
- time_t duration;
DBG("status %u", status);
@@ -746,18 +764,29 @@ static void conn_fail_cb(struct btd_device *dev, uint8_t status)
return;
}
- /* Give up if we've tried for too long */
- duration = time(NULL) - reconnect->start;
- if (duration + reconnect->timeout >= RECONNECT_GIVE_UP) {
+ /* Reset if ReconnectAttempts was reached */
+ if (reconnect->attempt == reconnect_attempts) {
reconnect_reset(reconnect);
return;
}
- reconnect->timer = g_timeout_add_seconds(reconnect->timeout,
- reconnect_timeout,
- reconnect);
+ reconnect_set_timer(reconnect);
+}
+
+static int policy_adapter_probe(struct btd_adapter *adapter)
+{
+ DBG("");
+
+ btd_adapter_restore_powered(adapter);
+
+ return 0;
}
+static struct btd_adapter_driver policy_driver = {
+ .name = "policy",
+ .probe = policy_adapter_probe,
+};
+
static int policy_init(void)
{
GError *gerr = NULL;
@@ -768,23 +797,53 @@ static int policy_init(void)
conf = btd_get_main_conf();
if (!conf) {
reconnect_uuids = g_strdupv((char **) default_reconnect);
- goto add_cb;
+ reconnect_attempts = default_attempts;
+ reconnect_intervals_len = sizeof(default_intervals) /
+ sizeof(*reconnect_intervals);
+ reconnect_intervals = g_memdup(default_intervals,
+ reconnect_intervals_len);
+ goto done;
}
reconnect_uuids = g_key_file_get_string_list(conf, "Policy",
"ReconnectUUIDs",
NULL, &gerr);
if (gerr) {
- g_error_free(gerr);
+ g_clear_error(&gerr);
reconnect_uuids = g_strdupv((char **) default_reconnect);
- goto add_cb;
}
-add_cb:
- if (reconnect_uuids && reconnect_uuids[0]) {
+
+ reconnect_attempts = g_key_file_get_integer(conf, "Policy",
+ "ReconnectAttempts",
+ &gerr);
+ if (gerr) {
+ g_clear_error(&gerr);
+ reconnect_attempts = default_attempts;
+ }
+
+ reconnect_intervals = g_key_file_get_integer_list(conf, "Policy",
+ "ReconnectIntervals",
+ (size_t *) &reconnect_intervals_len,
+ &gerr);
+ if (gerr) {
+ g_clear_error(&gerr);
+ reconnect_intervals_len = sizeof(default_intervals);
+ reconnect_intervals = g_memdup(default_intervals,
+ reconnect_intervals_len);
+ }
+
+ auto_enable = g_key_file_get_boolean(conf, "Policy", "AutoEnable",
+ NULL);
+
+done:
+ if (reconnect_uuids && reconnect_uuids[0] && reconnect_attempts) {
btd_add_disconnect_cb(disconnect_cb);
btd_add_conn_fail_cb(conn_fail_cb);
}
+ if (auto_enable)
+ btd_register_adapter_driver(&policy_driver);
+
return 0;
}
@@ -796,11 +855,16 @@ static void policy_exit(void)
if (reconnect_uuids)
g_strfreev(reconnect_uuids);
+ g_free(reconnect_intervals);
+
g_slist_free_full(reconnects, reconnect_destroy);
g_slist_free_full(devices, policy_remove);
btd_service_remove_state_cb(service_id);
+
+ if (auto_enable)
+ btd_unregister_adapter_driver(&policy_driver);
}
BLUETOOTH_PLUGIN_DEFINE(policy, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h
index 4d2584d0..e9da0bf8 100644
--- a/profiles/audio/a2dp-codecs.h
+++ b/profiles/audio/a2dp-codecs.h
@@ -141,6 +141,9 @@
#define APTX_SAMPLING_FREQ_44100 0x02
#define APTX_SAMPLING_FREQ_48000 0x01
+#define LDAC_VENDOR_ID 0x0000012d
+#define LDAC_CODEC_ID 0x00aa
+
typedef struct {
uint32_t vendor_id;
uint16_t codec_id;
@@ -186,6 +189,11 @@ typedef struct {
uint8_t frequency:4;
} __attribute__ ((packed)) a2dp_aptx_t;
+typedef struct {
+ a2dp_vendor_codec_t info;
+ uint8_t unknown[2];
+} __attribute__ ((packed)) a2dp_ldac_t;
+
#elif __BYTE_ORDER == __BIG_ENDIAN
typedef struct {
diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index 84786dec..2d5c7469 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -72,6 +72,9 @@ struct a2dp_sep {
struct avdtp *session;
struct avdtp_stream *stream;
guint suspend_timer;
+#ifdef __TIZEN_PATCH__
+ gboolean remote_suspended;
+#endif
gboolean delay_reporting;
gboolean locked;
gboolean suspending;
@@ -82,6 +85,7 @@ struct a2dp_sep {
struct a2dp_setup_cb {
struct a2dp_setup *setup;
+ a2dp_discover_cb_t discover_cb;
a2dp_select_cb_t select_cb;
a2dp_config_cb_t config_cb;
a2dp_stream_cb_t resume_cb;
@@ -98,6 +102,7 @@ struct a2dp_setup {
struct avdtp_stream *stream;
struct avdtp_error *err;
avdtp_set_configuration_cb setconf_cb;
+ GSList *seps;
GSList *caps;
gboolean reconfigure;
gboolean start;
@@ -302,6 +307,23 @@ static void finalize_select(struct a2dp_setup *s)
}
}
+static void finalize_discover(struct a2dp_setup *s)
+{
+ GSList *l;
+
+ for (l = s->cb; l != NULL; ) {
+ struct a2dp_setup_cb *cb = l->data;
+
+ l = l->next;
+
+ if (!cb->discover_cb)
+ continue;
+
+ cb->discover_cb(s->session, s->seps, s->err, cb->user_data);
+ setup_cb_free(cb);
+ }
+}
+
static struct a2dp_setup *find_setup_by_session(struct avdtp *session)
{
GSList *l;
@@ -375,6 +397,13 @@ static void stream_state_changed(struct avdtp_stream *stream,
return;
}
+#ifdef __TIZEN_PATCH__
+ if (new_state == AVDTP_STATE_STREAMING && sep->suspend_timer) {
+ g_source_remove(sep->suspend_timer);
+ sep->suspend_timer = 0;
+ }
+#endif
+
if (new_state != AVDTP_STATE_IDLE)
return;
@@ -799,12 +828,25 @@ static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
else
DBG("Source %p: Start_Ind", sep);
+#ifdef __TIZEN_PATCH__
+ if (!a2dp_sep->locked) {
+ a2dp_sep->session = avdtp_ref(session);
+ if(a2dp_sep->remote_suspended == FALSE)
+ a2dp_sep->suspend_timer = g_timeout_add_seconds(SUSPEND_TIMEOUT,
+ (GSourceFunc) suspend_timeout,
+ a2dp_sep);
+ else
+ a2dp_sep->remote_suspended = FALSE;
+ }
+#else
+
if (!a2dp_sep->locked) {
a2dp_sep->session = avdtp_ref(session);
a2dp_sep->suspend_timer = g_timeout_add_seconds(SUSPEND_TIMEOUT,
(GSourceFunc) suspend_timeout,
a2dp_sep);
}
+#endif
if (!a2dp_sep->starting)
return TRUE;
@@ -858,6 +900,10 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
else
DBG("Source %p: Suspend_Ind", sep);
+#ifdef __TIZEN_PATCH__
+ a2dp_sep->remote_suspended = TRUE;
+#endif
+
if (a2dp_sep->suspend_timer) {
g_source_remove(a2dp_sep->suspend_timer);
a2dp_sep->suspend_timer = 0;
@@ -1172,7 +1218,11 @@ static sdp_record_t *a2dp_record(uint8_t type)
sdp_data_t *psm, *version, *features;
uint16_t lp = AVDTP_UUID;
#ifdef __TIZEN_PATCH__
+#ifdef SUPPORT_LOCAL_DEVICE_A2DP_SINK
+ uint16_t a2dp_ver = 0x0102, avdtp_ver = 0x0103, feat = 0x0002;
+#else
uint16_t a2dp_ver = 0x0102, avdtp_ver = 0x0103, feat = 0x0001;
+#endif
#else
uint16_t a2dp_ver = 0x0103, avdtp_ver = 0x0103, feat = 0x000f;
#endif
@@ -1449,7 +1499,7 @@ static void transport_cb(GIOChannel *io, GError *err, gpointer user_data)
if (!avdtp_stream_set_transport(setup->stream,
g_io_channel_unix_get_fd(io),
- omtu, imtu))
+ imtu, omtu))
goto drop;
g_io_channel_set_close_on_unref(io, FALSE);
@@ -1535,6 +1585,9 @@ static bool a2dp_server_listen(struct a2dp_server *server)
btd_adapter_get_address(server->adapter),
BT_IO_OPT_PSM, AVDTP_PSM,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+#if defined(__TIZEN_PATCH__) && defined(SUPPORT_LOCAL_DEVICE_A2DP_SINK)
+ BT_IO_OPT_IMTU, 895,
+#endif
BT_IO_OPT_MASTER, true,
BT_IO_OPT_INVALID);
if (server->io)
@@ -1759,44 +1812,6 @@ done:
finalize_select(setup);
}
-#ifndef __TIZEN_PATCH__
-static gboolean check_vendor_codec(struct a2dp_sep *sep, uint8_t *cap,
- size_t len)
-{
- uint8_t *capabilities;
- size_t length;
- a2dp_vendor_codec_t *local_codec;
- a2dp_vendor_codec_t *remote_codec;
-
- if (len < sizeof(a2dp_vendor_codec_t))
- return FALSE;
-
- remote_codec = (a2dp_vendor_codec_t *) cap;
-
- if (sep->endpoint == NULL)
- return FALSE;
-
- length = sep->endpoint->get_capabilities(sep,
- &capabilities, sep->user_data);
-
- if (length < sizeof(a2dp_vendor_codec_t))
- return FALSE;
-
- local_codec = (a2dp_vendor_codec_t *) capabilities;
-
- if (btohl(remote_codec->vendor_id) != btohl(local_codec->vendor_id))
- return FALSE;
-
- if (btohs(remote_codec->codec_id) != btohs(local_codec->codec_id))
- return FALSE;
-
- DBG("vendor 0x%08x codec 0x%04x", btohl(remote_codec->vendor_id),
- btohs(remote_codec->codec_id));
-
- return TRUE;
-}
-#endif
-
static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
const char *sender)
{
@@ -1823,6 +1838,7 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
if (g_strcmp0(sender, name) != 0)
continue;
}
+
#ifdef __TIZEN_PATCH__
rsep = avdtp_find_remote_sep(session, sep->lsep);
if (rsep == NULL)
@@ -1836,9 +1852,8 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
continue;
}
#else
- if (check_vendor_codec(sep, cap->data,
- service->length - sizeof(*cap)))
- return sep;
+ if (avdtp_find_remote_sep(session, sep->lsep) == NULL)
+ continue;
#endif
return sep;
@@ -1876,6 +1891,40 @@ static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type,
return a2dp_find_sep(session, l, NULL);
}
+static void discover_cb(struct avdtp *session, GSList *seps,
+ struct avdtp_error *err, void *user_data)
+{
+ struct a2dp_setup *setup = user_data;
+
+ DBG("err %p", err);
+
+ setup->seps = seps;
+ setup->err = err;
+
+ finalize_discover(setup);
+}
+
+unsigned int a2dp_discover(struct avdtp *session, a2dp_discover_cb_t cb,
+ void *user_data)
+{
+ struct a2dp_setup *setup;
+ struct a2dp_setup_cb *cb_data;
+
+ setup = a2dp_setup_get(session);
+ if (!setup)
+ return 0;
+
+ cb_data = setup_cb_new(setup);
+ cb_data->discover_cb = cb;
+ cb_data->user_data = user_data;
+
+ if (avdtp_discover(session, discover_cb, setup) == 0)
+ return cb_data->id;
+
+ setup_cb_free(cb_data);
+ return 0;
+}
+
unsigned int a2dp_select_capabilities(struct avdtp *session,
uint8_t type, const char *sender,
a2dp_select_cb_t cb,
@@ -2169,8 +2218,8 @@ gboolean a2dp_cancel(unsigned int id)
if (!setup->cb) {
DBG("aborting setup %p", setup);
- avdtp_abort(setup->session, setup->stream);
- return TRUE;
+ if (!avdtp_abort(setup->session, setup->stream))
+ return TRUE;
}
setup_unref(setup);
@@ -2491,7 +2540,9 @@ static struct btd_adapter_driver media_driver = {
static int a2dp_init(void)
{
btd_register_adapter_driver(&media_driver);
+#if defined(__TIZEN_PATCH__) && defined(SUPPORT_LOCAL_DEVICE_A2DP_SINK)
btd_profile_register(&a2dp_source_profile);
+#endif
btd_profile_register(&a2dp_sink_profile);
return 0;
diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h
index 544eea1e..19d1877b 100644
--- a/profiles/audio/a2dp.h
+++ b/profiles/audio/a2dp.h
@@ -52,6 +52,9 @@ struct a2dp_endpoint {
void *user_data);
};
+typedef void (*a2dp_discover_cb_t) (struct avdtp *session, GSList *seps,
+ struct avdtp_error *err,
+ void *user_data);
typedef void (*a2dp_select_cb_t) (struct avdtp *session,
struct a2dp_sep *sep, GSList *caps,
void *user_data);
@@ -70,6 +73,9 @@ struct a2dp_sep *a2dp_add_sep(struct btd_adapter *adapter, uint8_t type,
int *err);
void a2dp_remove_sep(struct a2dp_sep *sep);
+
+unsigned int a2dp_discover(struct avdtp *session, a2dp_discover_cb_t cb,
+ void *user_data);
unsigned int a2dp_select_capabilities(struct avdtp *session,
uint8_t type, const char *sender,
a2dp_select_cb_t cb,
diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
index 34b01830..4c807276 100644
--- a/profiles/audio/avctp.c
+++ b/profiles/audio/avctp.c
@@ -320,16 +320,31 @@ static void send_key(int fd, uint16_t key, int pressed)
static gboolean auto_release(gpointer user_data)
{
struct avctp *session = user_data;
-
- session->key.timer = 0;
+#ifdef __TIZEN_PATCH__
+ uint16_t op = session->key.op;
+#endif
DBG("AV/C: key press timeout");
+#ifdef __TIZEN_PATCH__
+ if (op != KEY_FASTFORWARD && op != KEY_REWIND) {
+ session->key.timer = 0;
+ send_key(session->uinput, op, 0);
+ } else {
+ return TRUE;
+ }
+#else
+ session->key.timer = 0;
send_key(session->uinput, session->key.op, 0);
+#endif
return FALSE;
}
+#ifdef __TIZEN_PATCH__
+extern void avrcp_stop_position_timer(void);
+#endif
+
static void handle_press(struct avctp *session, uint16_t op)
{
if (session->key.timer > 0) {
@@ -338,8 +353,9 @@ static void handle_press(struct avctp *session, uint16_t op)
/* Only auto release if keys are different */
if (session->key.op == op)
goto done;
-
+#ifndef __TIZEN_PATCH__
send_key(session->uinput, session->key.op, 0);
+#endif
}
session->key.op = op;
@@ -797,7 +813,11 @@ static gboolean process_queue(void *user_data)
return FALSE;
chan->p = p;
+#ifdef __TIZEN_PATCH__
+ p->timeout = g_timeout_add_seconds(5, req_timeout, chan);
+#else
p->timeout = g_timeout_add_seconds(2, req_timeout, chan);
+#endif
return FALSE;
@@ -1446,6 +1466,16 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
if (!device)
return;
+#ifdef __TIZEN_PATCH__
+ char name[10];
+ device_get_name(device, name, sizeof(name));
+ DBG("name : %s", name);
+ if (g_str_equal(name, "PLT_M50")) {
+ DBG("Don't accept avrcp connection with this headset");
+ return;
+ }
+#endif
+
session = avctp_get_internal(device);
if (session == NULL)
return;
@@ -1702,13 +1732,20 @@ static gboolean repeat_timeout(gpointer user_data)
struct avctp *session = user_data;
avctp_passthrough_release(session, session->key.op);
+#ifndef __TIZEN_PATCH__
avctp_passthrough_press(session, session->key.op);
return TRUE;
+#else
+ return FALSE;
+#endif
}
static void release_pressed(struct avctp *session)
{
+#ifdef __TIZEN_PATCH__
+ if (session->key.op != AVC_FAST_FORWARD && session->key.op != AVC_REWIND)
+#endif
avctp_passthrough_release(session, session->key.op);
if (session->key.timer > 0)
@@ -1759,7 +1796,23 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op)
return avctp_passthrough_press(session, op);
}
+#ifdef __TIZEN_PATCH__
+int avctp_send_release_passthrough(struct avctp *session, uint8_t op)
+{
+ DBG("+");
+ if (op != AVC_FAST_FORWARD && op != AVC_REWIND)
+ return FALSE;
+
+ /* Auto release if key pressed */
+ if (session->key.timer > 0)
+ g_source_remove(session->key.timer);
+ session->key.timer = 0;
+
+ DBG("-");
+ return avctp_passthrough_release(session, op);
+}
+#endif
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
uint8_t code, uint8_t subunit,
uint8_t *operands, size_t operand_count)
diff --git a/profiles/audio/avctp.h b/profiles/audio/avctp.h
index 6c19ce42..b9329524 100644
--- a/profiles/audio/avctp.h
+++ b/profiles/audio/avctp.h
@@ -172,6 +172,9 @@ unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
gboolean avctp_unregister_browsing_pdu_handler(unsigned int id);
int avctp_send_passthrough(struct avctp *session, uint8_t op);
+#ifdef __TIZEN_PATCH__
+int avctp_send_release_passthrough(struct avctp *session, uint8_t op);
+#endif
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
uint8_t code, uint8_t subunit,
uint8_t *operands, size_t operand_count);
diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
index 0ba00b3d..07337027 100644
--- a/profiles/audio/avdtp.c
+++ b/profiles/audio/avdtp.c
@@ -42,7 +42,7 @@
#include "lib/uuid.h"
#ifdef __TIZEN_PATCH__
-#ifdef __BROADCOM_QOS_PATCH__
+#if defined(__BROADCOM_QOS_PATCH__) || defined(__SPRD_QOS_PATCH__)
#include <sys/ioctl.h>
#include <bluetooth/hci.h>
#endif /* __BROADCOM_QOS_PATCH__ */
@@ -961,7 +961,7 @@ static void handle_unanswered_req(struct avdtp *session,
#ifdef __TIZEN_PATCH__
#ifdef __BROADCOM_QOS_PATCH__
-static gboolean send_broadcom_a2dp_qos(bdaddr_t *dst, gboolean qos_high)
+static gboolean send_broadcom_a2dp_qos(const bdaddr_t *dst, gboolean qos_high)
{
int dd;
int err = 0;
@@ -1007,8 +1007,64 @@ static gboolean send_broadcom_a2dp_qos(bdaddr_t *dst, gboolean qos_high)
return TRUE;
}
#endif /* __BROADCOM_QOS_PATCH__ */
+
+#ifdef __SPRD_QOS_PATCH__
+static gboolean send_sprd_a2dp_qos(bdaddr_t *dst, gboolean qos_high)
+{
+ int dd;
+ int err = 0;
+ struct hci_conn_info_req *cr;
+ qos_setup_cp cp;
+
+ dd = hci_open_dev(0);
+
+ cr = g_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
+
+ cr->type = ACL_LINK;
+ bacpy(&cr->bdaddr, dst);
+
+ err = ioctl(dd, HCIGETCONNINFO, cr);
+ if (err < 0) {
+ error("Fail to get HCIGETCOINFO");
+ g_free(cr);
+ hci_close_dev(dd);
+ return FALSE;
+ }
+
+ cp.handle = cr->conn_info->handle;
+ cp.flags = 0x00;
+ DBG("Handle %d", cp.handle);
+ g_free(cr);
+
+ if (qos_high) {
+ cp.qos.service_type = 0x02;
+ cp.qos.token_rate = 0X000000C8;
+ cp.qos.peak_bandwidth = 0X000000C8;
+ cp.qos.latency = 0x00000001;
+ cp.qos.delay_variation = 0xFFFFFFFF;
+ } else {
+ cp.qos.service_type = 0x01;
+ cp.qos.token_rate = 0X00000000;
+ cp.qos.peak_bandwidth = 0X00000000;
+ cp.qos.latency = 0x00000001;
+ cp.qos.delay_variation = 0xFFFFFFFF;
+ }
+
+ if (hci_send_cmd(dd, OGF_LINK_POLICY, OCF_QOS_SETUP,
+ QOS_SETUP_CP_SIZE, &cp) < 0) {
+ hci_close_dev(dd);
+ return FALSE;
+ }
+ DBG("Send Spreadtrum Qos Patch %s", qos_high ? "High" : "Low");
+
+ hci_close_dev(dd);
+
+ return TRUE;
+}
+#endif /* __SPRD_QOS_PATCH__ */
+
#ifdef TIZEN_WEARABLE
-static gboolean fix_role_to_master(bdaddr_t *dst, gboolean fix_to_master)
+static gboolean fix_role_to_master(const bdaddr_t *dst, gboolean fix_to_master)
{
int dd;
int err = 0;
@@ -1074,11 +1130,12 @@ static void avdtp_sep_set_state(struct avdtp *session,
avdtp_state_t state)
{
struct avdtp_stream *stream = sep->stream;
-#ifdef __TIZEN_PATCH__
-#if defined(__BROADCOM_QOS_PATCH__) || defined(TIZEN_WEARABLE)
- bdaddr_t *dst;
- dst = (bdaddr_t*)device_get_address(session->device);
+#ifdef __TIZEN_PATCH__
+#if (defined(__BROADCOM_QOS_PATCH__) || defined(TIZEN_WEARABLE)) || \
+ defined(__SPRD_QOS_PATCH__)
+ const bdaddr_t *dst;
+ dst = device_get_address(session->device);
#endif
#endif
avdtp_state_t old_state;
@@ -1114,7 +1171,10 @@ static void avdtp_sep_set_state(struct avdtp *session,
#ifdef __TIZEN_PATCH__
#ifdef __BROADCOM_QOS_PATCH__
send_broadcom_a2dp_qos(dst, FALSE);
-#endif /* __BROADCOM_QOS_PATCH__ */
+#elif defined(__SPRD_QOS_PATCH__)
+ if (old_state == AVDTP_STATE_STREAMING)
+ send_sprd_a2dp_qos(dst, FALSE);
+#endif
#ifdef TIZEN_WEARABLE
fix_role_to_master(dst, FALSE);
#endif /* TIZEN_WEARABLE */
@@ -1130,7 +1190,10 @@ static void avdtp_sep_set_state(struct avdtp *session,
#ifdef __TIZEN_PATCH__
#ifdef __BROADCOM_QOS_PATCH__
send_broadcom_a2dp_qos(dst, TRUE);
-#endif /* __BROADCOM_QOS_PATCH__ */
+#elif defined(__SPRD_QOS_PATCH__)
+ if (old_state == AVDTP_STATE_OPEN)
+ send_sprd_a2dp_qos(dst, TRUE);
+#endif
#ifdef TIZEN_WEARABLE
fix_role_to_master(dst, TRUE);
#endif /* TIZEN_WEARABLE */
@@ -1274,6 +1337,7 @@ static void connection_lost(struct avdtp *session, int err)
if (service)
btd_service_connecting_complete(service, -err);
#endif
+
g_slist_foreach(session->streams, (GFunc) release_stream, session);
session->streams = NULL;
@@ -1326,6 +1390,7 @@ static gboolean disconnect_timeout(gpointer user_data)
return FALSE;
}
#endif
+
session->dc_timer = 0;
stream_setup = session->stream_setup;
@@ -1366,7 +1431,11 @@ static gboolean disconnect_timeout(gpointer user_data)
return FALSE;
}
+#if defined __TIZEN_PATCH__ && defined SUPPORT_LOCAL_DEVICE_A2DP_SINK
+static void set_disconnect_timer(struct avdtp *session, gboolean disconn)
+#else
static void set_disconnect_timer(struct avdtp *session)
+#endif
{
#ifdef __TIZEN_PATCH__
char name[6];
@@ -1376,15 +1445,31 @@ static void set_disconnect_timer(struct avdtp *session)
#ifdef __TIZEN_PATCH__
device_get_name(session->device, name, sizeof(name));
- DBG("name : %s", name);
- if (g_str_equal(name, "VW BT"))
+ DBG("name : [%s]", name);
+ if (g_str_equal(name, "VW BT") || g_str_equal(name, "VW MI") ||
+ g_str_equal(name, "Seat ")) {
session->dc_timer = g_timeout_add_seconds(3, disconnect_timeout,
session);
- else
+ } else if (g_str_equal(name, "CAR M")) {
+ session->dc_timer = g_timeout_add(200, disconnect_timeout,
+ session);
+ } else {
#endif
+#if defined __TIZEN_PATCH__ && defined SUPPORT_LOCAL_DEVICE_A2DP_SINK
+ if (disconn == TRUE)
+ session->dc_timer = g_timeout_add(100,
+ disconnect_timeout,
+ session);
+ else
+ session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT,
+ disconnect_timeout,
+ session);
+#else
session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT,
disconnect_timeout,
session);
+#endif
+ }
}
void avdtp_unref(struct avdtp *session)
@@ -1399,7 +1484,11 @@ void avdtp_unref(struct avdtp *session)
if (session->ref > 0)
return;
+#if defined __TIZEN_PATCH__ && defined SUPPORT_LOCAL_DEVICE_A2DP_SINK
+ set_disconnect_timer(session, TRUE);
+#else
set_disconnect_timer(session);
+#endif
}
struct avdtp *avdtp_ref(struct avdtp *session)
@@ -2540,7 +2629,11 @@ static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
NULL);
if (session->stream_setup)
+#if defined __TIZEN_PATCH__ && defined SUPPORT_LOCAL_DEVICE_A2DP_SINK
+ set_disconnect_timer(session, FALSE);
+#else
set_disconnect_timer(session);
+#endif
} else if (session->pending_open)
handle_transport_connect(session, chan, session->imtu,
session->omtu);
@@ -2614,6 +2707,9 @@ static GIOChannel *l2cap_connect(struct avdtp *session)
device_get_address(session->device),
BT_IO_OPT_PSM, AVDTP_PSM,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+#if defined __TIZEN_PATCH__ && defined SUPPORT_LOCAL_DEVICE_A2DP_SINK
+ BT_IO_OPT_IMTU, 895,
+#endif
BT_IO_OPT_INVALID);
if (!io) {
error("%s", err->message);
@@ -3628,11 +3724,43 @@ int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
/* If timer already active wait it */
if (stream->start_timer)
return 0;
+#ifdef __TIZEN_PATCH__
+ else {
+ char address[18];
+ uint32_t timeout_sec = START_TIMEOUT;
+
+ ba2str(device_get_address(session->device), address);
+ /* For Bose headset (Bose AE2w) 2 seconds timeout is required to avoid AVDTP ABORT_CMD */
+ if (!strncasecmp(address, "00:0C:8A", 8))
+ timeout_sec = 2;
+ /* For Gear Circle, HS3000 headset, this headset doesn't initiate start command and
+ * when we add timer for 1 second so idle may trigger callback after 1.2 sec or
+ * 1.5 sec. So, don't timer for this headset.*/
+ if (!strncasecmp(address, "10:92:66", 8) ||
+ !strncasecmp(address, "A8:9F:BA", 8)) {
+ start_timeout(stream);
+ return 0;
+ }
+ /* Here we can't use Mac address as there are changing so check for name */
+ char name[10];
+ device_get_name(session->device, name, sizeof(name));
+ DBG("name : %s", name);
+ if (g_str_equal(name, "HS3000")) {
+ start_timeout(stream);
+ return 0;
+ }
+ stream->start_timer = g_timeout_add_seconds(timeout_sec,
+ start_timeout,
+ stream);
+ return 0;
+ }
+#else
stream->start_timer = g_timeout_add_seconds(START_TIMEOUT,
start_timeout,
stream);
return 0;
+#endif
}
if (stream->close_int == TRUE) {
@@ -3709,6 +3837,13 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
struct seid_req req;
int ret;
+ if (!stream && session->discover) {
+ /* Don't call cb since it being aborted */
+ session->discover->cb = NULL;
+ finalize_discovery(session, -ECANCELED);
+ return -EALREADY;
+ }
+
if (!g_slist_find(session->streams, stream))
return -EINVAL;
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index a1e14114..72d49069 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -103,11 +103,13 @@
#define AVRCP_REQUEST_CONTINUING 0x40
#define AVRCP_ABORT_CONTINUING 0x41
#define AVRCP_SET_ABSOLUTE_VOLUME 0x50
+#define AVRCP_SET_ADDRESSED_PLAYER 0x60
#define AVRCP_SET_BROWSED_PLAYER 0x70
#define AVRCP_GET_FOLDER_ITEMS 0x71
#define AVRCP_CHANGE_PATH 0x72
#define AVRCP_GET_ITEM_ATTRIBUTES 0x73
#define AVRCP_PLAY_ITEM 0x74
+#define AVRCP_GET_TOTAL_NUMBER_OF_ITEMS 0x75
#define AVRCP_SEARCH 0x80
#define AVRCP_ADD_TO_NOW_PLAYING 0x90
#define AVRCP_GENERAL_REJECT 0xA0
@@ -135,6 +137,17 @@
#define AVRCP_CHARSET_UTF8 106
#define AVRCP_BROWSING_TIMEOUT 1
+#ifdef __TIZEN_PATCH__
+#define AVRCP_CT_VERSION 0x0103
+#define AVRCP_TG_VERSION 0x0103
+#else
+#define AVRCP_CT_VERSION 0x0106
+#define AVRCP_TG_VERSION 0x0105
+#endif
+#define AVRCP_SCOPE_MEDIA_PLAYER_LIST 0x00
+#define AVRCP_SCOPE_MEDIA_PLAYER_VFS 0x01
+#define AVRCP_SCOPE_SEARCH 0x02
+#define AVRCP_SCOPE_NOW_PLAYING 0x03
#if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -174,6 +187,30 @@ struct avrcp_browsing_header {
} __attribute__ ((packed));
#define AVRCP_BROWSING_HEADER_LENGTH 3
+struct get_folder_items_rsp {
+ uint8_t status;
+ uint16_t uid_counter;
+ uint16_t num_items;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct folder_item {
+ uint8_t type;
+ uint16_t len;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct player_item {
+ uint16_t player_id;
+ uint8_t type;
+ uint32_t subtype;
+ uint8_t status;
+ uint8_t features[16];
+ uint16_t charset;
+ uint16_t namelen;
+ char name[0];
+} __attribute__ ((packed));
+
struct avrcp_server {
struct btd_adapter *adapter;
uint32_t tg_record_id;
@@ -203,8 +240,10 @@ struct avrcp_player {
uint64_t uid;
uint16_t uid_counter;
bool browsed;
+ bool addressed;
uint8_t *features;
char *path;
+ guint changed_id;
struct pending_list_items *p;
char *change_path;
@@ -240,6 +279,9 @@ struct avrcp {
uint8_t transaction;
uint8_t transaction_events[AVRCP_EVENT_LAST + 1];
struct pending_pdu *pending_pdu;
+#ifdef __TIZEN_PATCH__
+ uint32_t playback_status_id;
+#endif
};
struct passthrough_handler {
@@ -255,22 +297,24 @@ struct control_pdu_handler {
};
static GSList *servers = NULL;
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
static unsigned int avctp_id = 0;
-#endif
-#ifdef SUPPORT_AVRCP_TARGET
#ifdef __TIZEN_PATCH__
+#ifdef SUPPORT_AVRCP_TARGET
static uint16_t adapter_avrcp_tg_ver = 0;
#endif
-#endif
-
#ifdef SUPPORT_AVRCP_CONTROL
-#ifdef __TIZEN_PATCH__
static uint16_t adapter_avrcp_ct_ver = 0;
#endif
#endif
+/* Default feature bit mask for media player as per avctp.c:key_map */
+static const uint8_t features[16] = {
+ 0xF8, 0xBF, 0xFF, 0xBF, 0x1F,
+ 0xFB, 0x3F, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00 };
+
/* Company IDs supported by this device */
static uint32_t company_ids[] = {
IEEEID_BTSIG,
@@ -295,7 +339,7 @@ static sdp_record_t *avrcp_ct_record(void)
sdp_data_t *psm[2], *version, *features;
uint16_t lp = AVCTP_CONTROL_PSM, ap = AVCTP_BROWSING_PSM;
#ifdef __TIZEN_PATCH__
- uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0104;
+ uint16_t avctp_ver = 0x0104;
uint16_t feat = 0;
#ifdef ENABLE_AVRCP_CATEGORY1
feat = AVRCP_FEATURE_CATEGORY_1;
@@ -304,7 +348,7 @@ static sdp_record_t *avrcp_ct_record(void)
feat = feat | AVRCP_FEATURE_CATEGORY_2;
#endif
#else
- uint16_t avrcp_ver = 0x0105, avctp_ver = 0x0103;
+ uint16_t avctp_ver = 0x0103;
uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
AVRCP_FEATURE_CATEGORY_2 |
AVRCP_FEATURE_CATEGORY_3 |
@@ -360,9 +404,9 @@ static sdp_record_t *avrcp_ct_record(void)
/* Bluetooth Profile Descriptor List */
sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
- profile[0].version = avrcp_ver;
+ profile[0].version = AVRCP_CT_VERSION;
#ifdef __TIZEN_PATCH__
- adapter_avrcp_ct_ver = avrcp_ver;
+ adapter_avrcp_ct_ver = AVRCP_CT_VERSION;
#endif
pfseq = sdp_list_append(NULL, &profile[0]);
sdp_set_profile_descs(record, pfseq);
@@ -407,7 +451,7 @@ static sdp_record_t *avrcp_tg_record(void)
uint16_t lp = AVCTP_CONTROL_PSM;
uint16_t lp_browsing = AVCTP_BROWSING_PSM;
#ifdef __TIZEN_PATCH__
- uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0104;
+ uint16_t avctp_ver = 0x0104;
uint16_t feat = 0;
#ifdef ENABLE_AVRCP_CATEGORY1
feat = AVRCP_FEATURE_CATEGORY_1 |
@@ -417,7 +461,7 @@ static sdp_record_t *avrcp_tg_record(void)
feat = feat | AVRCP_FEATURE_CATEGORY_2;
#endif
#else
- uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
+ uint16_t avctp_ver = 0x0103;
uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
AVRCP_FEATURE_CATEGORY_2 |
AVRCP_FEATURE_CATEGORY_3 |
@@ -469,9 +513,9 @@ static sdp_record_t *avrcp_tg_record(void)
/* Bluetooth Profile Descriptor List */
sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
- profile[0].version = avrcp_ver;
+ profile[0].version = AVRCP_TG_VERSION;
#ifdef __TIZEN_PATCH__
- adapter_avrcp_tg_ver = avrcp_ver;
+ adapter_avrcp_tg_ver = AVRCP_TG_VERSION;
#endif
pfseq = sdp_list_append(NULL, &profile[0]);
sdp_set_profile_descs(record, pfseq);
@@ -693,6 +737,7 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
{
uint8_t buf[AVRCP_HEADER_LENGTH + 9];
struct avrcp_header *pdu = (void *) buf;
+ uint8_t code;
uint16_t size;
GSList *l;
int attr;
@@ -710,10 +755,19 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
set_company_id(pdu->company_id, IEEEID_BTSIG);
pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
- pdu->params[0] = id;
DBG("id=%u", id);
+ if (id != AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED && player->changed_id) {
+ code = AVC_CTYPE_REJECTED;
+ size = 1;
+ pdu->params[0] = AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED;
+ goto done;
+ }
+
+ code = AVC_CTYPE_CHANGED;
+ pdu->params[0] = id;
+
switch (id) {
case AVRCP_EVENT_STATUS_CHANGED:
size = 2;
@@ -774,11 +828,20 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
memcpy(&pdu->params[1], position_val, sizeof(uint32_t));
break;
#endif
+ case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+ size = 5;
+ memcpy(&pdu->params[1], &player->id, sizeof(uint16_t));
+ memcpy(&pdu->params[3], &player->uid_counter, sizeof(uint16_t));
+ break;
+ case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+ size = 1;
+ break;
default:
error("Unknown event %u", id);
return;
}
+done:
pdu->params_len = htons(size);
#ifdef __TIZEN_PATCH__
if (id == AVRCP_EVENT_PLAYBACK_POS_CHANGED &&
@@ -801,8 +864,9 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
err = avctp_send_vendordep(session->conn,
session->transaction_events[id],
- AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
+ code, AVC_SUBUNIT_PANEL,
buf, size + AVRCP_HEADER_LENGTH);
+
if (err < 0)
continue;
@@ -1418,6 +1482,22 @@ static uint8_t player_get_status(struct avrcp_player *player)
return play_status_to_val(value);
}
+static uint16_t player_get_id(struct avrcp_player *player)
+{
+ if (player == NULL)
+ return 0x0000;
+
+ return player->id;
+}
+
+static uint16_t player_get_uid_counter(struct avrcp_player *player)
+{
+ if (player == NULL)
+ return 0x0000;
+
+ return player->uid_counter;
+}
+
static uint8_t avrcp_handle_get_play_status(struct avrcp *session,
struct avrcp_header *pdu,
uint8_t transaction)
@@ -1533,7 +1613,6 @@ static const struct passthrough_handler passthrough_handlers[] = {
{ },
};
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
static bool handle_passthrough(struct avctp *conn, uint8_t op, bool pressed,
void *user_data)
{
@@ -1555,7 +1634,6 @@ static bool handle_passthrough(struct avctp *conn, uint8_t op, bool pressed,
return handler->func(session);
}
-#endif
#ifdef __TIZEN_PATCH__
void avrcp_stop_position_timer(void)
@@ -1649,6 +1727,16 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
pdu->params[len++] = val;
}
+ g_list_free(settings);
+
+ break;
+ case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+ len = 5;
+ bt_put_be16(player_get_id(player), &pdu->params[1]);
+ bt_put_be16(player_get_uid_counter(player), &pdu->params[3]);
+ break;
+ case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+ len = 1;
break;
case AVRCP_EVENT_VOLUME_CHANGED:
pdu->params[1] = media_transport_get_device_volume(dev);
@@ -1782,19 +1870,12 @@ static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
struct avrcp_header *pdu,
uint8_t transaction)
{
-#ifndef __TIZEN_PATCH__
- struct avrcp_player *player = session->controller->player;
-#else
- struct avrcp_player *player = target_get_player(session);
-#endif
uint16_t len = ntohs(pdu->params_len);
uint8_t volume;
if (len != 1)
goto err;
- if (!player)
- goto err;
volume = pdu->params[0] & 0x7F;
@@ -1808,6 +1889,90 @@ err:
return AVC_CTYPE_REJECTED;
}
+static struct avrcp_player *find_tg_player(struct avrcp *session, uint16_t id)
+{
+ struct avrcp_server *server = session->server;
+ GSList *l;
+
+ for (l = server->players; l; l = l->next) {
+ struct avrcp_player *player = l->data;
+
+ if (player->id == id)
+ return player;
+ }
+
+ return NULL;
+}
+
+static gboolean notify_addressed_player_changed(gpointer user_data)
+{
+ struct avrcp_player *player = user_data;
+ uint8_t events[6] = { AVRCP_EVENT_STATUS_CHANGED,
+ AVRCP_EVENT_TRACK_CHANGED,
+ AVRCP_EVENT_TRACK_REACHED_START,
+ AVRCP_EVENT_TRACK_REACHED_END,
+ AVRCP_EVENT_SETTINGS_CHANGED,
+ AVRCP_EVENT_PLAYBACK_POS_CHANGED
+ };
+ uint8_t i;
+
+ avrcp_player_event(player, AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED, NULL);
+
+ /*
+ * TG shall complete all player specific
+ * notifications with AV/C C-Type REJECTED
+ * with error code as Addressed Player Changed.
+ */
+ for (i = 0; i < sizeof(events); i++)
+ avrcp_player_event(player, events[i], NULL);
+
+ player->changed_id = 0;
+
+ return FALSE;
+}
+
+static uint8_t avrcp_handle_set_addressed_player(struct avrcp *session,
+ struct avrcp_header *pdu,
+ uint8_t transaction)
+{
+ struct avrcp_player *player;
+ uint16_t len = ntohs(pdu->params_len);
+ uint16_t player_id = 0;
+ uint8_t status;
+
+ if (len < 1) {
+ status = AVRCP_STATUS_INVALID_PARAM;
+ goto err;
+ }
+
+ player_id = bt_get_be16(&pdu->params[0]);
+ player = find_tg_player(session, player_id);
+ pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+ if (player) {
+ player->addressed = true;
+ status = AVRCP_STATUS_SUCCESS;
+ pdu->params_len = htons(len);
+ pdu->params[0] = status;
+ } else {
+ status = AVRCP_STATUS_INVALID_PLAYER_ID;
+ goto err;
+ }
+
+ /* Don't emit player changed immediately since PTS expect the
+ * response of SetAddressedPlayer before the event.
+ */
+ player->changed_id = g_idle_add(notify_addressed_player_changed,
+ player);
+
+ return AVC_CTYPE_ACCEPTED;
+
+err:
+ pdu->params_len = htons(sizeof(status));
+ pdu->params[0] = status;
+ return AVC_CTYPE_REJECTED;
+}
+
static const struct control_pdu_handler control_handlers[] = {
{ AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
avrcp_handle_get_capabilities },
@@ -1839,10 +2004,11 @@ static const struct control_pdu_handler control_handlers[] = {
avrcp_handle_request_continuing },
{ AVRCP_ABORT_CONTINUING, AVC_CTYPE_CONTROL,
avrcp_handle_abort_continuing },
+ { AVRCP_SET_ADDRESSED_PLAYER, AVC_CTYPE_CONTROL,
+ avrcp_handle_set_addressed_player },
{ },
};
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
/* handle vendordep pdu inside an avctp packet */
static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
uint8_t *code, uint8_t *subunit,
@@ -1902,14 +2068,124 @@ err_metadata:
return AVRCP_HEADER_LENGTH + 1;
}
+static void avrcp_handle_media_player_list(struct avrcp *session,
+ struct avrcp_browsing_header *pdu,
+ uint32_t start_item, uint32_t end_item)
+{
+ struct avrcp_player *player = session->target->player;
+ struct get_folder_items_rsp *rsp;
+ const char *name = NULL;
+ GSList *l;
+
+ rsp = (void *)pdu->params;
+ rsp->status = AVRCP_STATUS_SUCCESS;
+ rsp->uid_counter = htons(player_get_uid_counter(player));
+ rsp->num_items = 0;
+ pdu->param_len = sizeof(*rsp);
+
+ for (l = g_slist_nth(session->server->players, start_item);
+ l; l = g_slist_next(l)) {
+ struct avrcp_player *player = l->data;
+ struct folder_item *folder;
+ struct player_item *item;
+ uint16_t namelen;
+
+ if (rsp->num_items == (end_item - start_item) + 1)
+ break;
+
+ folder = (void *)&pdu->params[pdu->param_len];
+ folder->type = 0x01; /* Media Player */
+
+ pdu->param_len += sizeof(*folder);
+
+ item = (void *)folder->data;
+ item->player_id = htons(player->id);
+ item->type = 0x01; /* Audio */
+ item->subtype = htonl(0x01); /* Audio Book */
+ item->status = player_get_status(player);
+ /* Assign Default Feature Bit Mask */
+ memcpy(&item->features, &features, sizeof(features));
+
+ item->charset = htons(AVRCP_CHARSET_UTF8);
+
+ name = player->cb->get_name(player->user_data);
+ namelen = strlen(name);
+ item->namelen = htons(namelen);
+ memcpy(item->name, name, namelen);
+
+ folder->len = htons(sizeof(*item) + namelen);
+ pdu->param_len += sizeof(*item) + namelen;
+ rsp->num_items++;
+ }
+
+ /* If no player could be found respond with an error */
+ if (!rsp->num_items)
+ goto failed;
+
+ rsp->num_items = htons(rsp->num_items);
+ pdu->param_len = htons(pdu->param_len);
+
+ return;
+
+failed:
+ pdu->params[0] = AVRCP_STATUS_OUT_OF_BOUNDS;
+ pdu->param_len = htons(1);
+}
+
+static void avrcp_handle_get_folder_items(struct avrcp *session,
+ struct avrcp_browsing_header *pdu,
+ uint8_t transaction)
+{
+ uint32_t start_item = 0;
+ uint32_t end_item = 0;
+ uint8_t scope;
+ uint8_t status = AVRCP_STATUS_SUCCESS;
+
+ if (ntohs(pdu->param_len) < 10) {
+ status = AVRCP_STATUS_INVALID_PARAM;
+ goto failed;
+ }
+
+ scope = pdu->params[0];
+ start_item = bt_get_be32(&pdu->params[1]);
+ end_item = bt_get_be32(&pdu->params[5]);
+
+ DBG("scope 0x%02x start_item 0x%08x end_item 0x%08x", scope,
+ start_item, end_item);
+
+ if (end_item < start_item) {
+ status = AVRCP_STATUS_INVALID_PARAM;
+ goto failed;
+ }
+
+ switch (scope) {
+ case AVRCP_SCOPE_MEDIA_PLAYER_LIST:
+ avrcp_handle_media_player_list(session, pdu,
+ start_item, end_item);
+ break;
+ case AVRCP_SCOPE_MEDIA_PLAYER_VFS:
+ case AVRCP_SCOPE_SEARCH:
+ case AVRCP_SCOPE_NOW_PLAYING:
+ default:
+ status = AVRCP_STATUS_INVALID_PARAM;
+ goto failed;
+ }
+
+ return;
+
+failed:
+ pdu->params[0] = status;
+ pdu->param_len = htons(1);
+}
+
static struct browsing_pdu_handler {
uint8_t pdu_id;
void (*func) (struct avrcp *session, struct avrcp_browsing_header *pdu,
uint8_t transaction);
} browsing_handlers[] = {
+ { AVRCP_GET_FOLDER_ITEMS, avrcp_handle_get_folder_items },
{ },
};
-#endif
size_t avrcp_browsing_general_reject(uint8_t *operands)
{
@@ -1924,7 +2200,6 @@ size_t avrcp_browsing_general_reject(uint8_t *operands)
return AVRCP_BROWSING_HEADER_LENGTH + sizeof(status);
}
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
static size_t handle_browsing_pdu(struct avctp *conn,
uint8_t transaction, uint8_t *operands,
size_t operand_count, void *user_data)
@@ -1948,7 +2223,6 @@ done:
handler->func(session, pdu, transaction);
return AVRCP_BROWSING_HEADER_LENGTH + ntohs(pdu->param_len);
}
-#endif
size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands)
{
@@ -2107,7 +2381,6 @@ static gboolean avrcp_player_value_rsp(struct avctp *conn,
return FALSE;
}
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
static void avrcp_get_current_player_value(struct avrcp *session,
uint8_t *attrs, uint8_t count)
{
@@ -2181,7 +2454,6 @@ static void avrcp_list_player_attributes(struct avrcp *session)
avrcp_list_player_attributes_rsp,
session);
}
-#endif
static void avrcp_parse_attribute_list(struct avrcp_player *player,
uint8_t *operands, uint8_t count)
@@ -2756,7 +3028,25 @@ static int ct_press(struct avrcp_player *player, uint8_t op)
return 0;
}
+#ifdef __TIZEN_PATCH__
+static int ct_release(struct avrcp_player *player, uint8_t op)
+{
+ DBG("+");
+ int err;
+ struct avrcp *session;
+
+ session = player->sessions->data;
+ if (session == NULL)
+ return -ENOTCONN;
+ err = avctp_send_release_passthrough(session->conn, op);
+ if (err < 0)
+ return err;
+
+ DBG("-");
+ return 0;
+}
+#endif
static int ct_play(struct media_player *mp, void *user_data)
{
struct avrcp_player *player = user_data;
@@ -2791,7 +3081,43 @@ static int ct_previous(struct media_player *mp, void *user_data)
return ct_press(player, AVC_BACKWARD);
}
+#ifdef __TIZEN_PATCH__
+static int ct_press_fast_forward(struct media_player *mp, void *user_data)
+{
+ DBG("+");
+ struct avrcp_player *player = user_data;
+
+ DBG("-");
+ return ct_press(player, AVC_FAST_FORWARD);
+}
+
+static int ct_release_fast_forward(struct media_player *mp, void *user_data)
+{
+ DBG("+");
+ struct avrcp_player *player = user_data;
+
+ DBG("-");
+ return ct_release(player, AVC_FAST_FORWARD);
+}
+
+static int ct_press_rewind(struct media_player *mp, void *user_data)
+{
+ DBG("+");
+ struct avrcp_player *player = user_data;
+
+ DBG("-");
+ return ct_press(player, AVC_REWIND);
+}
+static int ct_release_rewind(struct media_player *mp, void *user_data)
+{
+ DBG("+");
+ struct avrcp_player *player = user_data;
+
+ DBG("-");
+ return ct_release(player, AVC_REWIND);
+}
+#else
static int ct_fast_forward(struct media_player *mp, void *user_data)
{
struct avrcp_player *player = user_data;
@@ -2805,7 +3131,7 @@ static int ct_rewind(struct media_player *mp, void *user_data)
return ct_press(player, AVC_REWIND);
}
-
+#endif
static int ct_list_items(struct media_player *mp, const char *name,
uint32_t start, uint32_t end, void *user_data)
{
@@ -2953,7 +3279,7 @@ static void avrcp_play_item(struct avrcp *session, uint64_t uid)
length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
- avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+ avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL,
AVC_SUBUNIT_PANEL, buf, length,
NULL, session);
}
@@ -2999,7 +3325,7 @@ static void avrcp_add_to_nowplaying(struct avrcp *session, uint64_t uid)
length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
- avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+ avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL,
AVC_SUBUNIT_PANEL, buf, length,
NULL, session);
}
@@ -3025,6 +3351,78 @@ static int ct_add_to_nowplaying(struct media_player *mp, const char *name,
return 0;
}
+static gboolean avrcp_get_total_numberofitems_rsp(struct avctp *conn,
+ uint8_t *operands, size_t operand_count,
+ void *user_data)
+{
+ struct avrcp_browsing_header *pdu = (void *) operands;
+ struct avrcp *session = user_data;
+ struct avrcp_player *player = session->controller->player;
+ struct media_player *mp = player->user_data;
+ uint32_t num_of_items;
+
+ if (pdu == NULL)
+ return -ETIMEDOUT;
+
+ if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 7)
+ return -EINVAL;
+
+ if (pdu->params[0] == AVRCP_STATUS_OUT_OF_BOUNDS)
+ goto done;
+
+ player->uid_counter = get_be16(&pdu->params[1]);
+ num_of_items = get_be32(&pdu->params[3]);
+
+ if (!num_of_items)
+ return -EINVAL;
+
+done:
+ media_player_total_items_complete(mp, num_of_items);
+ return FALSE;
+}
+
+static void avrcp_get_total_numberofitems(struct avrcp *session)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 7];
+ struct avrcp_player *player = session->controller->player;
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_GET_TOTAL_NUMBER_OF_ITEMS;
+ pdu->param_len = htons(7 + sizeof(uint32_t));
+
+ pdu->params[0] = player->scope;
+
+ avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+ avrcp_get_total_numberofitems_rsp, session);
+}
+
+static int ct_get_total_numberofitems(struct media_player *mp, const char *name,
+ void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct avrcp *session;
+
+ session = player->sessions->data;
+
+ if (session->controller->version != 0x0106) {
+ error("version not supported");
+ return -1;
+ }
+
+ if (g_str_has_prefix(name, "/NowPlaying"))
+ player->scope = 0x03;
+ else if (g_str_has_suffix(name, "/search"))
+ player->scope = 0x02;
+ else
+ player->scope = 0x01;
+
+ avrcp_get_total_numberofitems(session);
+
+ return 0;
+}
+
static const struct media_player_callback ct_cbs = {
.set_setting = ct_set_setting,
.play = ct_play,
@@ -3032,15 +3430,32 @@ static const struct media_player_callback ct_cbs = {
.stop = ct_stop,
.next = ct_next,
.previous = ct_previous,
+#ifdef __TIZEN_PATCH__
+ .press_fast_forward = ct_press_fast_forward,
+ .release_fast_forward = ct_release_fast_forward,
+ .press_rewind = ct_press_rewind,
+ .release_rewind = ct_release_rewind,
+#else
.fast_forward = ct_fast_forward,
.rewind = ct_rewind,
+#endif
.list_items = ct_list_items,
.change_folder = ct_change_folder,
.search = ct_search,
.play_item = ct_play_item,
.add_to_nowplaying = ct_add_to_nowplaying,
+ .total_items = ct_get_total_numberofitems,
};
+static void set_ct_player(struct avrcp *session, struct avrcp_player *player)
+{
+ struct btd_service *service;
+
+ session->controller->player = player;
+ service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
+ control_set_player(service, media_player_get_path(player->user_data));
+}
+
static struct avrcp_player *create_ct_player(struct avrcp *session,
uint16_t id)
{
@@ -3062,7 +3477,7 @@ static struct avrcp_player *create_ct_player(struct avrcp *session,
player->destroy = (GDestroyNotify) media_player_destroy;
if (session->controller->player == NULL)
- session->controller->player = player;
+ set_ct_player(session, player);
session->controller->players = g_slist_prepend(
session->controller->players,
@@ -3157,6 +3572,9 @@ static void player_destroy(gpointer data)
avrcp_stop_position_timer();
#endif
+ if (player->changed_id > 0)
+ g_source_remove(player->changed_id);
+
g_slist_free(player->sessions);
g_free(player->path);
g_free(player->change_path);
@@ -3171,10 +3589,15 @@ static void player_remove(gpointer data)
for (l = player->sessions; l; l = l->next) {
struct avrcp *session = l->data;
+ struct avrcp_data *controller = session->controller;
- session->controller->players = g_slist_remove(
- session->controller->players,
- player);
+ controller->players = g_slist_remove(controller->players,
+ player);
+
+ /* Check if current player is being removed */
+ if (controller->player == player)
+ set_ct_player(session, g_slist_nth_data(
+ controller->players, 0));
}
player_destroy(player);
@@ -3225,9 +3648,6 @@ static gboolean avrcp_get_media_player_list_rsp(struct avctp *conn,
i += len;
}
- if (g_slist_find(removed, session->controller->player))
- session->controller->player = NULL;
-
g_slist_free_full(removed, player_remove);
return FALSE;
@@ -3241,6 +3661,8 @@ static void avrcp_get_media_player_list(struct avrcp *session)
memset(buf, 0, sizeof(buf));
pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS;
+ put_be32(0, &pdu->params[1]);
+ put_be32(UINT32_MAX, &pdu->params[5]);
pdu->param_len = htons(10);
avctp_send_browsing_req(session->conn, buf, sizeof(buf),
@@ -3292,6 +3714,17 @@ static void avrcp_track_changed(struct avrcp *session,
avrcp_get_element_attributes(session);
}
+static void avrcp_playback_pos_changed(struct avrcp *session,
+ struct avrcp_header *pdu)
+{
+ struct avrcp_player *player = session->controller->player;
+ struct media_player *mp = player->user_data;
+ uint32_t position;
+
+ position = get_be32(&pdu->params[1]);
+ media_player_set_position(mp, position);
+}
+
static void avrcp_setting_changed(struct avrcp *session,
struct avrcp_header *pdu)
{
@@ -3339,7 +3772,7 @@ static void avrcp_addressed_player_changed(struct avrcp *session,
}
player->uid_counter = get_be16(&pdu->params[3]);
- session->controller->player = player;
+ set_ct_player(session, player);
if (player->features != NULL)
return;
@@ -3385,6 +3818,9 @@ static gboolean avrcp_handle_event(struct avctp *conn,
case AVRCP_EVENT_TRACK_CHANGED:
avrcp_track_changed(session, pdu);
break;
+ case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
+ avrcp_playback_pos_changed(session, pdu);
+ break;
case AVRCP_EVENT_SETTINGS_CHANGED:
avrcp_setting_changed(session, pdu);
break;
@@ -3416,6 +3852,14 @@ static void avrcp_register_notification(struct avrcp *session, uint8_t event)
pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
pdu->params[0] = event;
+
+ /*
+ * Set maximum interval possible for position changed as we only
+ * use it to resync.
+ */
+ if (event == AVRCP_EVENT_PLAYBACK_POS_CHANGED)
+ bt_put_be32(UINT32_MAX / 1000, &pdu->params[1]);
+
pdu->params_len = htons(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH);
length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
@@ -3425,7 +3869,37 @@ static void avrcp_register_notification(struct avrcp *session, uint8_t event)
avrcp_handle_event, session);
}
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
+#ifdef __TIZEN_PATCH__
+static char *avrcp_event_to_string(uint8_t event)
+{
+
+ switch (event) {
+ case AVRCP_EVENT_STATUS_CHANGED:
+ return "AVRCP EVENT STATUS CHANGED";
+ case AVRCP_EVENT_TRACK_CHANGED:
+ return "AVRCP EVENT TRACK CHANGED";
+ case AVRCP_EVENT_SETTINGS_CHANGED:
+ return "AVRCP EVENT SETTINGS CHANGED";
+ case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+ return "AVRCP EVENT ADDRESSED PLAYER CHANGED";
+ case AVRCP_EVENT_UIDS_CHANGED:
+ return "AVRCP EVENT UIDS CHANGED";
+ case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+ return "AVRCP EVENT AVAILABLE PLAYERS CHANGED";
+ case AVRCP_EVENT_VOLUME_CHANGED:
+ return "AVRCP EVENT VOLUME CHANGED";
+ default:
+ return "Unknown Event";
+ }
+}
+
+static gboolean avrcp_get_playback_status(struct avrcp *session)
+{
+ avrcp_get_play_status(session);
+ return TRUE;
+}
+#endif
+
static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
uint8_t code, uint8_t subunit,
uint8_t *operands, size_t operand_count,
@@ -3453,10 +3927,13 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
uint8_t event = pdu->params[1 + count];
events |= (1 << event);
-
+#ifdef __TIZEN_PATCH__
+ DBG("Supported Event %s", avrcp_event_to_string(event));
+#endif
switch (event) {
case AVRCP_EVENT_STATUS_CHANGED:
case AVRCP_EVENT_TRACK_CHANGED:
+ case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
case AVRCP_EVENT_SETTINGS_CHANGED:
#ifndef __TIZEN_PATCH__
case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
@@ -3483,7 +3960,12 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
avrcp_get_element_attributes(session);
-
+#ifdef __TIZEN_PATCH__
+ if ((events & (1 << AVRCP_EVENT_STATUS_CHANGED)) == 0) {
+ session->playback_status_id = g_timeout_add_seconds(1,
+ avrcp_get_playback_status, session);
+ }
+#endif
return FALSE;
}
@@ -3508,7 +3990,6 @@ static void avrcp_get_capabilities(struct avrcp *session)
avrcp_get_capabilities_resp,
session);
}
-#endif
static struct avrcp *find_session(GSList *list, struct btd_device *dev)
{
@@ -3522,7 +4003,6 @@ static struct avrcp *find_session(GSList *list, struct btd_device *dev)
return NULL;
}
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
static void destroy_browsing(void *data)
{
struct avrcp *session = data;
@@ -3596,7 +4076,6 @@ static void avrcp_connect_browsing(struct avrcp *session)
connect_browsing,
session);
}
-#endif
#ifdef SUPPORT_AVRCP_TARGET
static void target_init(struct avrcp *session)
@@ -3642,6 +4121,11 @@ static void target_init(struct avrcp *session)
return;
#endif
+ session->supported_events |=
+ (1 << AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED) |
+ (1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED) |
+ (1 << AVRCP_EVENT_VOLUME_CHANGED);
+
/* Only check capabilities if controller is not supported */
if (session->controller == NULL)
avrcp_get_capabilities(session);
@@ -3664,13 +4148,6 @@ static void controller_init(struct avrcp *session)
return;
controller = data_init(session, AVRCP_TARGET_UUID);
-#ifdef __TIZEN_PATCH__
- /* Fix : NULL_RETURNS */
- if (controller == NULL) {
- error("controller is NULL");
- return;
- }
-#endif
session->controller = controller;
DBG("%p version 0x%04x", controller, controller->version);
@@ -3678,9 +4155,6 @@ static void controller_init(struct avrcp *session)
#ifdef __TIZEN_PATCH__
if ((controller->version >= 0x0104) && (adapter_avrcp_ct_ver >= 0x0104))
session->supported_events |= (1 << AVRCP_EVENT_VOLUME_CHANGED);
-#else
- if (controller->version >= 0x0104)
- session->supported_events |= (1 << AVRCP_EVENT_VOLUME_CHANGED);
#endif
service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
@@ -3714,7 +4188,6 @@ static void controller_init(struct avrcp *session)
}
#endif
-#if defined(SUPPORT_AVRCP_TARGET) || defined(SUPPORT_AVRCP_CONTROL)
static void session_init_control(struct avrcp *session)
{
session->passthrough_id = avctp_register_passthrough_handler(
@@ -3768,6 +4241,14 @@ static void session_destroy(struct avrcp *session, int err)
server->sessions = g_slist_remove(server->sessions, session);
+#ifdef __TIZEN_PATCH__
+ if (session->playback_status_id > 0) {
+ DBG("Removing the timer for playback status polling");
+ g_source_remove(session->playback_status_id);
+ session->playback_status_id = 0;
+ }
+#endif
+
session_abort_pending_pdu(session);
service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
@@ -3907,7 +4388,6 @@ static void avrcp_server_unregister(struct avrcp_server *server)
avctp_id = 0;
}
}
-#endif
struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
struct avrcp_player_cb *cb,
@@ -3917,12 +4397,14 @@ struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
struct avrcp_server *server;
struct avrcp_player *player;
GSList *l;
+ static uint16_t id = 0;
server = find_server(servers, adapter);
if (!server)
return NULL;
player = g_new0(struct avrcp_player, 1);
+ player->id = ++id;
player->server = server;
player->cb = cb;
player->user_data = user_data;
@@ -3945,6 +4427,9 @@ struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
}
}
+ avrcp_player_event(player,
+ AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED, NULL);
+
return player;
}
@@ -3967,6 +4452,9 @@ void avrcp_unregister_player(struct avrcp_player *player)
target->player = g_slist_nth_data(server->players, 0);
}
+ avrcp_player_event(player,
+ AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED, NULL);
+
player_destroy(player);
}
@@ -3992,7 +4480,53 @@ static gboolean avrcp_handle_set_volume(struct avctp *conn,
return FALSE;
}
-int avrcp_set_volume(struct btd_device *dev, uint8_t volume)
+static int avrcp_event(struct avrcp *session, uint8_t id, const void *data)
+{
+ uint8_t buf[AVRCP_HEADER_LENGTH + 2];
+ struct avrcp_header *pdu = (void *) buf;
+ uint8_t code;
+ uint16_t size;
+ int err;
+
+ /* Verify that the event is registered */
+ if (!(session->registered_events & (1 << id)))
+ return -ENOENT;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+ pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
+ code = AVC_CTYPE_CHANGED;
+ pdu->params[0] = id;
+
+ DBG("id=%u", id);
+
+ switch (id) {
+ case AVRCP_EVENT_VOLUME_CHANGED:
+ size = 2;
+ memcpy(&pdu->params[1], data, sizeof(uint8_t));
+ break;
+ default:
+ error("Unknown event %u", id);
+ return -EINVAL;
+ }
+
+ pdu->params_len = htons(size);
+
+ err = avctp_send_vendordep(session->conn,
+ session->transaction_events[id],
+ code, AVC_SUBUNIT_PANEL,
+ buf, size + AVRCP_HEADER_LENGTH);
+ if (err < 0)
+ return err;
+
+ /* Unregister event as per AVRCP 1.3 spec, section 5.4.2 */
+ session->registered_events ^= 1 << id;
+
+ return err;
+}
+
+int avrcp_set_volume(struct btd_device *dev, uint8_t volume, bool notify)
{
struct avrcp_server *server;
struct avrcp *session;
@@ -4004,18 +4538,23 @@ int avrcp_set_volume(struct btd_device *dev, uint8_t volume)
return -EINVAL;
session = find_session(server->sessions, dev);
- if (session == NULL || session->target == NULL)
+ if (session == NULL)
return -ENOTCONN;
- if (session->target->version < 0x0104)
+ if (notify) {
+ if (!session->target)
+ return -ENOTSUP;
+ return avrcp_event(session, AVRCP_EVENT_VOLUME_CHANGED,
+ &volume);
+ }
+
+ if (!session->controller || session->controller->version < 0x0104)
return -ENOTSUP;
memset(buf, 0, sizeof(buf));
set_company_id(pdu->company_id, IEEEID_BTSIG);
- DBG("volume=%u", volume);
-
pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME;
pdu->params[0] = volume;
pdu->params_len = htons(1);
@@ -4030,9 +4569,19 @@ static int avrcp_connect(struct btd_service *service)
{
struct btd_device *dev = btd_service_get_device(service);
const char *path = device_get_path(dev);
-
+#ifdef __TIZEN_PATCH__
+ char name[10];
+#endif
DBG("path %s", path);
+#ifdef __TIZEN_PATCH__
+ device_get_name(dev, name, sizeof(name));
+ DBG("name : %s", name);
+ if (g_str_equal(name, "PLT_M50")) {
+ DBG("Don't initiate avrcp connection with this headset");
+ return -ENOTSUP;
+ }
+#endif
return control_connect(service);
}
diff --git a/profiles/audio/avrcp.h b/profiles/audio/avrcp.h
index 28074db5..86d310c7 100644
--- a/profiles/audio/avrcp.h
+++ b/profiles/audio/avrcp.h
@@ -74,9 +74,7 @@
#define AVRCP_EVENT_TRACK_CHANGED 0x02
#define AVRCP_EVENT_TRACK_REACHED_END 0x03
#define AVRCP_EVENT_TRACK_REACHED_START 0x04
-#ifdef __TIZEN_PATCH__
-#define AVRCP_EVENT_PLAYBACK_POS_CHANGED 0x05
-#endif
+#define AVRCP_EVENT_PLAYBACK_POS_CHANGED 0x05
#define AVRCP_EVENT_SETTINGS_CHANGED 0x08
#define AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED 0x0a
#define AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED 0x0b
@@ -95,6 +93,7 @@ struct avrcp_player_cb {
const char *(*get_status) (void *user_data);
uint32_t (*get_position) (void *user_data);
uint32_t (*get_duration) (void *user_data);
+ const char *(*get_name) (void *user_data);
void (*set_volume) (uint8_t volume, struct btd_device *dev,
void *user_data);
bool (*play) (void *user_data);
@@ -104,7 +103,7 @@ struct avrcp_player_cb {
bool (*previous) (void *user_data);
};
-int avrcp_set_volume(struct btd_device *dev, uint8_t volume);
+int avrcp_set_volume(struct btd_device *dev, uint8_t volume, bool notify);
struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
struct avrcp_player_cb *cb,
diff --git a/profiles/audio/control.c b/profiles/audio/control.c
index f4656d85..edc4a98c 100644
--- a/profiles/audio/control.c
+++ b/profiles/audio/control.c
@@ -59,6 +59,7 @@
#include "avctp.h"
#include "control.h"
+#include "player.h"
static GSList *devices = NULL;
@@ -68,6 +69,7 @@ struct control {
struct btd_service *target;
struct btd_service *remote;
unsigned int avctp_id;
+ const char *player;
};
static void state_changed(struct btd_device *dev, avctp_state_t old_state,
@@ -81,9 +83,12 @@ static void state_changed(struct btd_device *dev, avctp_state_t old_state,
switch (new_state) {
case AVCTP_STATE_DISCONNECTED:
control->session = NULL;
+ control->player = NULL;
g_dbus_emit_property_changed(conn, path,
AUDIO_CONTROL_INTERFACE, "Connected");
+ g_dbus_emit_property_changed(conn, path,
+ AUDIO_CONTROL_INTERFACE, "Player");
break;
case AVCTP_STATE_CONNECTING:
@@ -215,21 +220,46 @@ static gboolean control_property_get_connected(
return TRUE;
}
+static gboolean control_player_exists(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct control *control = data;
+
+ return control->player != NULL;
+}
+
+static gboolean control_get_player(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct control *control = data;
+
+ if (!control->player)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+ &control->player);
+
+ return TRUE;
+}
+
static const GDBusMethodTable control_methods[] = {
- { GDBUS_METHOD("Play", NULL, NULL, control_play) },
- { GDBUS_METHOD("Pause", NULL, NULL, control_pause) },
- { GDBUS_METHOD("Stop", NULL, NULL, control_stop) },
- { GDBUS_METHOD("Next", NULL, NULL, control_next) },
- { GDBUS_METHOD("Previous", NULL, NULL, control_previous) },
- { GDBUS_METHOD("VolumeUp", NULL, NULL, control_volume_up) },
- { GDBUS_METHOD("VolumeDown", NULL, NULL, control_volume_down) },
- { GDBUS_METHOD("FastForward", NULL, NULL, control_fast_forward) },
- { GDBUS_METHOD("Rewind", NULL, NULL, control_rewind) },
+ { GDBUS_DEPRECATED_METHOD("Play", NULL, NULL, control_play) },
+ { GDBUS_DEPRECATED_METHOD("Pause", NULL, NULL, control_pause) },
+ { GDBUS_DEPRECATED_METHOD("Stop", NULL, NULL, control_stop) },
+ { GDBUS_DEPRECATED_METHOD("Next", NULL, NULL, control_next) },
+ { GDBUS_DEPRECATED_METHOD("Previous", NULL, NULL, control_previous) },
+ { GDBUS_DEPRECATED_METHOD("VolumeUp", NULL, NULL, control_volume_up) },
+ { GDBUS_DEPRECATED_METHOD("VolumeDown", NULL, NULL,
+ control_volume_down) },
+ { GDBUS_DEPRECATED_METHOD("FastForward", NULL, NULL,
+ control_fast_forward) },
+ { GDBUS_DEPRECATED_METHOD("Rewind", NULL, NULL, control_rewind) },
{ }
};
static const GDBusPropertyTable control_properties[] = {
{ "Connected", "b", control_property_get_connected },
+ { "Player", "o", control_get_player, NULL, control_player_exists },
{ }
};
@@ -338,3 +368,22 @@ int control_init_remote(struct btd_service *service)
return 0;
}
+
+int control_set_player(struct btd_service *service, const char *path)
+{
+ struct control *control = btd_service_get_user_data(service);
+
+ if (!control->session)
+ return -ENOTCONN;
+
+ if (g_strcmp0(control->player, path) == 0)
+ return -EALREADY;
+
+ control->player = path;
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ device_get_path(control->dev),
+ AUDIO_CONTROL_INTERFACE, "Player");
+
+ return 0;
+}
diff --git a/profiles/audio/control.h b/profiles/audio/control.h
index 4bda8968..aab2631b 100644
--- a/profiles/audio/control.h
+++ b/profiles/audio/control.h
@@ -32,3 +32,5 @@ void control_unregister(struct btd_service *service);
int control_connect(struct btd_service *service);
int control_disconnect(struct btd_service *service);
+
+int control_set_player(struct btd_service *service, const char *path);
diff --git a/profiles/audio/media.c b/profiles/audio/media.c
index 35566829..dacdc5f4 100644
--- a/profiles/audio/media.c
+++ b/profiles/audio/media.c
@@ -62,6 +62,7 @@
#include "sink.h"
#endif
+
#define MEDIA_INTERFACE "org.bluez.Media1"
#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
#define MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
@@ -130,6 +131,7 @@ struct media_player {
bool next;
bool previous;
bool control;
+ char *name;
};
static GSList *adapters = NULL;
@@ -504,16 +506,30 @@ static void media_sink_state_changed_cb(struct btd_service *service,
if ((old_state == SINK_STATE_PLAYING) &&
(new_state == SINK_STATE_CONNECTED)) {
+#ifdef __TIZEN_PATCH__
+ struct btd_device *device = btd_service_get_device(service);
+ char name[20] = {0,};
+#endif
+
/* Check AVRCP play back status */
if (g_strcmp0(mp->status, "playing") != 0)
return;
media_stop_suspend_timer();
+#ifdef __TIZEN_PATCH__
+ device_get_name(device, name, sizeof(name));
+ DBG("Name : %s", name);
+
+ if (g_str_has_prefix(name, "LG HBS") != TRUE) {
+#endif
/* PlayBackStatus is still PLAYING; start a timer */
suspend_timer_id = g_timeout_add_seconds(SINK_SUSPEND_TIMEOUT,
media_reset_mp_status, mp);
DBG("SINK SUSPEND TIMEOUT started");
+#ifdef __TIZEN_PATCH__
+ }
+#endif
}
/* Check if A2DP streaming is started */
@@ -521,7 +537,11 @@ static void media_sink_state_changed_cb(struct btd_service *service,
(new_state == SINK_STATE_PLAYING)) {
struct btd_device *device = btd_service_get_device(service);
+#ifdef __TIZEN_PATCH__
+ char name[20] = {0,};
+#else
char name[20];
+#endif
media_stop_suspend_timer();
@@ -705,8 +725,8 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size,
void *user_data)
{
struct a2dp_config_data *data = user_data;
-
- data->cb(data->setup, ret ? TRUE : FALSE);
+ gboolean *ret_value = ret;
+ data->cb(data->setup, ret_value ? *ret_value : FALSE);
}
static int set_config(struct a2dp_sep *sep, uint8_t *configuration,
@@ -1153,6 +1173,7 @@ static void media_player_free(gpointer data)
g_free(mp->sender);
g_free(mp->path);
g_free(mp->status);
+ g_free(mp->name);
g_free(mp);
}
@@ -1201,6 +1222,13 @@ static const char *get_setting(const char *key, void *user_data)
return g_hash_table_lookup(mp->settings, key);
}
+static const char *get_player_name(void *user_data)
+{
+ struct media_player *mp = user_data;
+
+ return mp->name;
+}
+
static void set_shuffle_setting(DBusMessageIter *iter, const char *value)
{
const char *key = "Shuffle";
@@ -1466,6 +1494,7 @@ static struct avrcp_player_cb player_cb = {
.get_position = get_position,
.get_duration = get_duration,
.get_status = get_status,
+ .get_name = get_player_name,
.set_volume = set_volume,
.play = play,
.stop = stop,
@@ -1506,7 +1535,8 @@ static gboolean set_status(struct media_player *mp, DBusMessageIter *iter)
avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, mp->status);
#ifdef __TIZEN_PATCH__
- if (strcasecmp(mp->status, "reverse-seek") != 0) {
+ if (strcasecmp(mp->status, "reverse-seek") != 0 &&
+ strcasecmp(mp->status, "playing") != 0) {
playback_position = get_position(mp);
avrcp_player_event(mp->player, AVRCP_EVENT_PLAYBACK_POS_CHANGED,
&playback_position);
@@ -1877,6 +1907,25 @@ static gboolean set_flag(struct media_player *mp, DBusMessageIter *iter,
return TRUE;
}
+static gboolean set_name(struct media_player *mp, DBusMessageIter *iter)
+{
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ if (g_strcmp0(mp->name, value) == 0)
+ return TRUE;
+
+ g_free(mp->name);
+
+ mp->name = g_strdup(value);
+
+ return TRUE;
+}
+
static gboolean set_player_property(struct media_player *mp, const char *key,
DBusMessageIter *entry)
{
@@ -1917,6 +1966,9 @@ static gboolean set_player_property(struct media_player *mp, const char *key,
if (strcasecmp(key, "CanControl") == 0)
return set_flag(mp, &var, &mp->control);
+ if (strcasecmp(key, "Identity") == 0)
+ return set_name(mp, &var);
+
DBG("%s not supported, ignoring", key);
return TRUE;
@@ -2105,19 +2157,11 @@ static const GDBusMethodTable media_methods[] = {
NULL, register_endpoint) },
{ GDBUS_METHOD("UnregisterEndpoint",
GDBUS_ARGS({ "endpoint", "o" }), NULL, unregister_endpoint) },
-#ifndef __TIZEN_PATCH__
- { GDBUS_EXPERIMENTAL_METHOD("RegisterPlayer",
- GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }),
- NULL, register_player) },
- { GDBUS_EXPERIMENTAL_METHOD("UnregisterPlayer",
- GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
-#else
{ GDBUS_METHOD("RegisterPlayer",
GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }),
NULL, register_player) },
{ GDBUS_METHOD("UnregisterPlayer",
GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
-#endif /* __TIZEN_PATCH__ */
{ },
};
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 94eb2eba..e7ee747f 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -534,7 +534,83 @@ static DBusMessage *media_player_previous(DBusConnection *conn,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+#ifdef __TIZEN_PATCH__
+static DBusMessage *media_player_press_fast_forward(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBG("+");
+ struct media_player *mp = data;
+ struct player_callback *cb = mp->cb;
+ int err;
+
+ if (cb->cbs->press_fast_forward == NULL)
+ return btd_error_not_supported(msg);
+
+ err = cb->cbs->press_fast_forward(mp, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ DBG("-");
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+static DBusMessage *media_player_release_fast_forward(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBG("+");
+ struct media_player *mp = data;
+ struct player_callback *cb = mp->cb;
+ int err;
+
+ if (cb->cbs->release_fast_forward == NULL)
+ return btd_error_not_supported(msg);
+
+ err = cb->cbs->release_fast_forward(mp, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ DBG("-");
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_press_rewind(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ DBG("+");
+ struct media_player *mp = data;
+ struct player_callback *cb = mp->cb;
+ int err;
+
+ if (cb->cbs->press_rewind == NULL)
+ return btd_error_not_supported(msg);
+
+ err = cb->cbs->press_rewind(mp, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ DBG("-");
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_release_rewind(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ DBG("+");
+ struct media_player *mp = data;
+ struct player_callback *cb = mp->cb;
+ int err;
+
+ if (cb->cbs->release_rewind == NULL)
+ return btd_error_not_supported(msg);
+
+ err = cb->cbs->release_rewind(mp, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ DBG("-");
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+#else
static DBusMessage *media_player_fast_forward(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -568,7 +644,7 @@ static DBusMessage *media_player_rewind(DBusConnection *conn, DBusMessage *msg,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
-
+#endif
static void parse_folder_list(gpointer data, gpointer user_data)
{
struct media_item *item = data;
@@ -702,14 +778,38 @@ done:
folder->msg = NULL;
}
+void media_player_total_items_complete(struct media_player *mp,
+ uint32_t num_of_items)
+{
+ struct media_folder *folder = mp->scope;
+
+ if (folder == NULL || folder->msg == NULL)
+ return;
+
+ if (folder->number_of_items != num_of_items) {
+ folder->number_of_items = num_of_items;
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ mp->path, MEDIA_FOLDER_INTERFACE,
+ "NumberOfItems");
+ }
+}
+
static const GDBusMethodTable media_player_methods[] = {
{ GDBUS_METHOD("Play", NULL, NULL, media_player_play) },
{ GDBUS_METHOD("Pause", NULL, NULL, media_player_pause) },
{ GDBUS_METHOD("Stop", NULL, NULL, media_player_stop) },
{ GDBUS_METHOD("Next", NULL, NULL, media_player_next) },
{ GDBUS_METHOD("Previous", NULL, NULL, media_player_previous) },
+#ifdef __TIZEN_PATCH__
+ { GDBUS_METHOD("PressFastForward", NULL, NULL, media_player_press_fast_forward) },
+ { GDBUS_METHOD("ReleaseFastForward", NULL, NULL, media_player_release_fast_forward) },
+ { GDBUS_METHOD("PressRewind", NULL, NULL, media_player_press_rewind) },
+ { GDBUS_METHOD("ReleaseRewind", NULL, NULL, media_player_release_rewind) },
+#else
{ GDBUS_METHOD("FastForward", NULL, NULL, media_player_fast_forward) },
{ GDBUS_METHOD("Rewind", NULL, NULL, media_player_rewind) },
+#endif
{ }
};
@@ -891,6 +991,9 @@ static void media_folder_destroy(void *data)
static void media_player_change_scope(struct media_player *mp,
struct media_folder *folder)
{
+ struct player_callback *cb = mp->cb;
+ int err;
+
if (mp->scope == folder)
return;
@@ -920,10 +1023,19 @@ cleanup:
done:
mp->scope = folder;
+ if (cb->cbs->total_items) {
+ err = cb->cbs->total_items(mp, folder->item->name,
+ cb->user_data);
+ if (err < 0)
+ DBG("Failed to get total num of items");
+ } else {
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ mp->path, MEDIA_FOLDER_INTERFACE,
+ "NumberOfItems");
+ }
+
g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
MEDIA_FOLDER_INTERFACE, "Name");
- g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
- MEDIA_FOLDER_INTERFACE, "NumberOfItems");
}
static struct media_folder *find_folder(GSList *folders, const char *pattern)
@@ -1164,6 +1276,11 @@ struct media_player *media_player_controller_create(const char *path,
return mp;
}
+const char *media_player_get_path(struct media_player *mp)
+{
+ return mp->path;
+}
+
void media_player_set_duration(struct media_player *mp, uint32_t duration)
{
char *value, *curval;
@@ -1297,17 +1414,34 @@ void media_player_set_metadata(struct media_player *mp,
void *data, size_t len)
{
char *value, *curval;
+#ifdef __TIZEN_PATCH__
+ char *end, *temp;
+#endif
value = g_strndup(data, len);
+#ifdef __TIZEN_PATCH__
+ temp = value;
+ while (g_utf8_validate(temp, -1, &end) == FALSE) {
+ temp = g_utf8_find_next_char(end, NULL);
+ if (temp == NULL) {
+ *end = '\0';
+ break;
+ }
+ strcpy(end, temp);
+ temp = end;
+ }
+#endif
+
DBG("%s: %s", key, value);
curval = g_hash_table_lookup(mp->track, key);
+#ifndef __TIZEN_PATCH__
if (g_strcmp0(curval, value) == 0) {
g_free(value);
return;
}
-
+#endif
if (mp->process_id == 0) {
g_hash_table_remove_all(mp->track);
mp->process_id = g_idle_add(process_metadata_changed, mp);
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index ac2a3daf..c560ec2a 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -52,8 +52,15 @@ struct media_player_callback {
int (*stop) (struct media_player *mp, void *user_data);
int (*next) (struct media_player *mp, void *user_data);
int (*previous) (struct media_player *mp, void *user_data);
+#ifdef __TIZEN_PATCH__
+ int (*press_fast_forward) (struct media_player *mp, void *user_data);
+ int (*release_fast_forward) (struct media_player *mp, void *user_data);
+ int (*press_rewind) (struct media_player *mp, void *user_data);
+ int (*release_rewind) (struct media_player *mp, void *user_data);
+#else
int (*fast_forward) (struct media_player *mp, void *user_data);
int (*rewind) (struct media_player *mp, void *user_data);
+#endif
int (*list_items) (struct media_player *mp, const char *name,
uint32_t start, uint32_t end, void *user_data);
int (*change_folder) (struct media_player *mp, const char *path,
@@ -64,10 +71,13 @@ struct media_player_callback {
uint64_t uid, void *user_data);
int (*add_to_nowplaying) (struct media_player *mp, const char *name,
uint64_t uid, void *user_data);
+ int (*total_items) (struct media_player *mp, const char *name,
+ void *user_data);
};
struct media_player *media_player_controller_create(const char *path,
uint16_t id);
+const char *media_player_get_path(struct media_player *mp);
void media_player_destroy(struct media_player *mp);
void media_player_set_duration(struct media_player *mp, uint32_t duration);
void media_player_set_position(struct media_player *mp, uint32_t position);
@@ -104,6 +114,8 @@ void media_player_list_complete(struct media_player *mp, GSList *items,
void media_player_change_folder_complete(struct media_player *player,
const char *path, int ret);
void media_player_search_complete(struct media_player *mp, int ret);
+void media_player_total_items_complete(struct media_player *mp,
+ uint32_t num_of_items);
void media_player_set_callbacks(struct media_player *mp,
const struct media_player_callback *cbs,
diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
index 78a68872..e2751abc 100644
--- a/profiles/audio/sink.c
+++ b/profiles/audio/sink.c
@@ -242,6 +242,8 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
struct sink *sink = user_data;
int id, perr;
+ sink->connect_id = 0;
+
if (err) {
avdtp_unref(sink->session);
sink->session = NULL;
@@ -287,7 +289,9 @@ gboolean sink_setup_stream(struct btd_service *service, struct avdtp *session)
if (!sink->session)
return FALSE;
- if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
+ sink->connect_id = a2dp_discover(sink->session, discovery_complete,
+ sink);
+ if (sink->connect_id == 0)
return FALSE;
return TRUE;
@@ -441,7 +445,7 @@ int sink_disconnect(struct btd_service *service)
if (sink->connect_id > 0) {
a2dp_cancel(sink->connect_id);
sink->connect_id = 0;
- btd_service_connecting_complete(sink->service, -ECANCELED);
+ btd_service_disconnecting_complete(sink->service, 0);
avdtp_unref(sink->session);
sink->session = NULL;
diff --git a/profiles/audio/source.c b/profiles/audio/source.c
index b235a7d9..372b1320 100644
--- a/profiles/audio/source.c
+++ b/profiles/audio/source.c
@@ -227,6 +227,8 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
struct source *source = user_data;
int id, perr;
+ source->connect_id = 0;
+
if (err) {
avdtp_unref(source->session);
source->session = NULL;
@@ -273,7 +275,9 @@ gboolean source_setup_stream(struct btd_service *service,
if (!source->session)
return FALSE;
- if (avdtp_discover(source->session, discovery_complete, source) < 0)
+ source->connect_id = a2dp_discover(source->session, discovery_complete,
+ source);
+ if (source->connect_id == 0)
return FALSE;
return TRUE;
@@ -398,7 +402,7 @@ int source_disconnect(struct btd_service *service)
if (source->connect_id > 0) {
a2dp_cancel(source->connect_id);
source->connect_id = 0;
- btd_service_connecting_complete(source->service, -ECANCELED);
+ btd_service_disconnecting_complete(source->service, 0);
avdtp_unref(source->session);
source->session = NULL;
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index 91b9cae9..9c18edd0 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -676,6 +676,7 @@ static void set_volume(const GDBusPropertyTable *property,
struct media_transport *transport = data;
struct a2dp_transport *a2dp = transport->data;
uint16_t volume;
+ bool notify;
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) {
g_dbus_pending_property_error(id,
@@ -693,12 +694,21 @@ static void set_volume(const GDBusPropertyTable *property,
return;
}
- if (a2dp->volume != volume)
- avrcp_set_volume(transport->device, volume);
+ g_dbus_pending_property_success(id);
+
+ if (a2dp->volume == volume)
+ return;
a2dp->volume = volume;
- g_dbus_pending_property_success(id);
+ notify = transport->source_watch ? true : false;
+ if (notify)
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "Volume");
+
+ avrcp_set_volume(transport->device, volume, notify);
}
static const GDBusMethodTable transport_methods[] = {
@@ -840,7 +850,6 @@ static int media_transport_init_sink(struct media_transport *transport)
transport->destroy = destroy_a2dp;
a2dp->volume = 127;
- avrcp_set_volume(transport->device, a2dp->volume);
transport->source_watch = source_add_state_cb(service,
source_state_changed,
transport);
diff --git a/profiles/battery/bas.c b/profiles/battery/bas.c
new file mode 100644
index 00000000..de369fd3
--- /dev/null
+++ b/profiles/battery/bas.c
@@ -0,0 +1,340 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can rebastribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is bastributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "src/log.h"
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+
+#include "profiles/battery/bas.h"
+
+#define ATT_NOTIFICATION_HEADER_SIZE 3
+#define ATT_READ_RESPONSE_HEADER_SIZE 1
+
+struct bt_bas {
+ int ref_count;
+ GAttrib *attrib;
+ struct gatt_primary *primary;
+ uint16_t handle;
+ uint16_t ccc_handle;
+ guint id;
+ struct queue *gatt_op;
+};
+
+struct gatt_request {
+ unsigned int id;
+ struct bt_bas *bas;
+ void *user_data;
+};
+
+static void destroy_gatt_req(struct gatt_request *req)
+{
+ queue_remove(req->bas->gatt_op, req);
+ bt_bas_unref(req->bas);
+ free(req);
+}
+
+static void bas_free(struct bt_bas *bas)
+{
+ bt_bas_detach(bas);
+
+ g_free(bas->primary);
+ queue_destroy(bas->gatt_op, (void *) destroy_gatt_req);
+ free(bas);
+}
+
+struct bt_bas *bt_bas_new(void *primary)
+{
+ struct bt_bas *bas;
+
+ bas = new0(struct bt_bas, 1);
+ bas->gatt_op = queue_new();
+
+ if (primary)
+ bas->primary = g_memdup(primary, sizeof(*bas->primary));
+
+ return bt_bas_ref(bas);
+}
+
+struct bt_bas *bt_bas_ref(struct bt_bas *bas)
+{
+ if (!bas)
+ return NULL;
+
+ __sync_fetch_and_add(&bas->ref_count, 1);
+
+ return bas;
+}
+
+void bt_bas_unref(struct bt_bas *bas)
+{
+ if (!bas)
+ return;
+
+ if (__sync_sub_and_fetch(&bas->ref_count, 1))
+ return;
+
+ bas_free(bas);
+}
+
+static struct gatt_request *create_request(struct bt_bas *bas,
+ void *user_data)
+{
+ struct gatt_request *req;
+
+ req = new0(struct gatt_request, 1);
+ req->user_data = user_data;
+ req->bas = bt_bas_ref(bas);
+
+ return req;
+}
+
+static void set_and_store_gatt_req(struct bt_bas *bas,
+ struct gatt_request *req,
+ unsigned int id)
+{
+ req->id = id;
+ queue_push_head(bas->gatt_op, req);
+}
+
+static void write_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
+ const uint8_t *value, size_t vlen,
+ GAttribResultFunc func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(bas, user_data);
+
+ id = gatt_write_char(attrib, handle, value, vlen, func, req);
+
+ set_and_store_gatt_req(bas, req, id);
+}
+
+static void read_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
+ GAttribResultFunc func, gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(bas, user_data);
+
+ id = gatt_read_char(attrib, handle, func, req);
+
+ set_and_store_gatt_req(bas, req, id);
+}
+
+static void discover_char(struct bt_bas *bas, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(bas, user_data);
+
+ id = gatt_discover_char(attrib, start, end, uuid, func, req);
+
+ set_and_store_gatt_req(bas, req, id);
+}
+
+static void discover_desc(struct bt_bas *bas, GAttrib *attrib,
+ uint16_t start, uint16_t end, bt_uuid_t *uuid,
+ gatt_cb_t func, gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(bas, user_data);
+
+ id = gatt_discover_desc(attrib, start, end, uuid, func, req);
+ set_and_store_gatt_req(bas, req, id);
+}
+
+static void notification_cb(const guint8 *pdu, guint16 len, gpointer user_data)
+{
+ DBG("Battery Level at %u", pdu[ATT_NOTIFICATION_HEADER_SIZE]);
+}
+
+static void read_value_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ DBG("Battery Level at %u", pdu[ATT_READ_RESPONSE_HEADER_SIZE]);
+}
+
+static void ccc_written_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_bas *bas = req->user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Write Scan Refresh CCC failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ DBG("Battery Level: notification enabled");
+
+ bas->id = g_attrib_register(bas->attrib, ATT_OP_HANDLE_NOTIFY,
+ bas->handle, notification_cb, bas,
+ NULL);
+}
+
+static void write_ccc(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
+ void *user_data)
+{
+ uint8_t value[2];
+
+ put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+
+ write_char(bas, attrib, handle, value, sizeof(value), ccc_written_cb,
+ user_data);
+}
+
+static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_bas *bas = req->user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Error reading CCC value: %s", att_ecode2str(status));
+ return;
+ }
+
+ write_ccc(bas, bas->attrib, bas->ccc_handle, bas);
+}
+
+static void discover_descriptor_cb(uint8_t status, GSList *descs,
+ void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_bas *bas = req->user_data;
+ struct gatt_desc *desc;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Discover descriptors failed: %s", att_ecode2str(status));
+ return;
+ }
+
+ /* There will be only one descriptor on list and it will be CCC */
+ desc = descs->data;
+ bas->ccc_handle = desc->handle;
+
+ read_char(bas, bas->attrib, desc->handle, ccc_read_cb, bas);
+}
+
+static void bas_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_bas *bas = req->user_data;
+ struct gatt_char *chr;
+ uint16_t start, end;
+ bt_uuid_t uuid;
+
+ destroy_gatt_req(req);
+
+ if (status) {
+ error("Battery: %s", att_ecode2str(status));
+ return;
+ }
+
+ chr = chars->data;
+ bas->handle = chr->value_handle;
+
+ DBG("Battery handle: 0x%04x", bas->handle);
+
+ read_char(bas, bas->attrib, bas->handle, read_value_cb, bas);
+
+ start = chr->value_handle + 1;
+ end = bas->primary->range.end;
+
+ bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+ discover_desc(bas, bas->attrib, start, end, &uuid,
+ discover_descriptor_cb, bas);
+}
+
+bool bt_bas_attach(struct bt_bas *bas, void *attrib)
+{
+ if (!bas || bas->attrib || !bas->primary)
+ return false;
+
+ bas->attrib = g_attrib_ref(attrib);
+
+ if (bas->handle > 0)
+ return true;
+
+ discover_char(bas, bas->attrib, bas->primary->range.start,
+ bas->primary->range.end, NULL,
+ bas_discovered_cb, bas);
+
+ return true;
+}
+
+static void cancel_gatt_req(struct gatt_request *req)
+{
+ if (g_attrib_cancel(req->bas->attrib, req->id))
+ destroy_gatt_req(req);
+}
+
+void bt_bas_detach(struct bt_bas *bas)
+{
+ if (!bas || !bas->attrib)
+ return;
+
+ if (bas->id > 0) {
+ g_attrib_unregister(bas->attrib, bas->id);
+ bas->id = 0;
+ }
+
+ queue_foreach(bas->gatt_op, (void *) cancel_gatt_req, NULL);
+ g_attrib_unref(bas->attrib);
+ bas->attrib = NULL;
+}
diff --git a/profiles/battery/bas.h b/profiles/battery/bas.h
new file mode 100644
index 00000000..3e175b5b
--- /dev/null
+++ b/profiles/battery/bas.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can rebastribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is bastributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bt_bas;
+
+struct bt_bas *bt_bas_new(void *primary);
+
+struct bt_bas *bt_bas_ref(struct bt_bas *bas);
+void bt_bas_unref(struct bt_bas *bas);
+
+bool bt_bas_attach(struct bt_bas *bas, void *gatt);
+void bt_bas_detach(struct bt_bas *bas);
diff --git a/profiles/deviceinfo/deviceinfo.c b/profiles/deviceinfo/deviceinfo.c
index a0e9951e..d1f51a02 100644
--- a/profiles/deviceinfo/deviceinfo.c
+++ b/profiles/deviceinfo/deviceinfo.c
@@ -3,6 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2012 Texas Instruments, Inc.
+ * Copyright (C) 2015 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,161 +39,113 @@
#include "src/device.h"
#include "src/profile.h"
#include "src/service.h"
-#include "src/shared/util.h"
#include "attrib/gattrib.h"
-#include "src/attio.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
#include "attrib/att.h"
-#include "attrib/gatt.h"
#include "src/log.h"
#define PNP_ID_SIZE 7
-struct deviceinfo {
- struct btd_device *dev; /* Device reference */
- GAttrib *attrib; /* GATT connection */
- guint attioid; /* Att watcher id */
- struct att_range *svc_range; /* DeviceInfo range */
- GSList *chars; /* Characteristics */
-};
-
-struct characteristic {
- struct gatt_char attr; /* Characteristic */
- struct deviceinfo *d; /* deviceinfo where the char belongs */
-};
-
-static void deviceinfo_driver_remove(struct btd_service *service)
+static void read_pnpid_cb(bool success, uint8_t att_ecode, const uint8_t *value,
+ uint16_t length, void *user_data)
{
- struct deviceinfo *d = btd_service_get_user_data(service);
-
- if (d->attioid > 0)
- btd_device_remove_attio_callback(d->dev, d->attioid);
-
- if (d->attrib != NULL)
- g_attrib_unref(d->attrib);
-
- g_slist_free_full(d->chars, g_free);
+ struct btd_device *device = user_data;
- btd_device_unref(d->dev);
- g_free(d->svc_range);
- g_free(d);
-}
-
-static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct characteristic *ch = user_data;
- uint8_t value[PNP_ID_SIZE];
- ssize_t vlen;
-
- if (status != 0) {
- error("Error reading PNP_ID value: %s", att_ecode2str(status));
+ if (!success) {
+ error("Error reading PNP_ID value: %s",
+ att_ecode2str(att_ecode));
return;
}
- vlen = dec_read_resp(pdu, len, value, sizeof(value));
- if (vlen < 0) {
- error("Error reading PNP_ID: Protocol error");
- return;
- }
-
- if (vlen < 7) {
+ if (length < PNP_ID_SIZE) {
error("Error reading PNP_ID: Invalid pdu length received");
return;
}
- btd_device_set_pnpid(ch->d->dev, value[0], get_le16(&value[1]),
+ btd_device_set_pnpid(device, value[0], get_le16(&value[1]),
get_le16(&value[3]), get_le16(&value[5]));
}
-static void process_deviceinfo_char(struct characteristic *ch)
+static void handle_pnpid(struct btd_device *device, uint16_t value_handle)
{
- if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
- gatt_read_char(ch->d->attrib, ch->attr.value_handle,
- read_pnpid_cb, ch);
+ struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+
+ if (!bt_gatt_client_read_value(client, value_handle,
+ read_pnpid_cb, device, NULL))
+ DBG("Failed to send request to read pnpid");
}
-static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
+static void handle_characteristic(struct gatt_db_attribute *attr,
void *user_data)
{
- struct deviceinfo *d = user_data;
- GSList *l;
+ struct btd_device *device = user_data;
+ uint16_t value_handle;
+ bt_uuid_t uuid, pnpid_uuid;
+
+ bt_string_to_uuid(&pnpid_uuid, PNPID_UUID);
- if (status != 0) {
- error("Discover deviceinfo characteristics: %s",
- att_ecode2str(status));
+ if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL,
+ &uuid)) {
+ error("Failed to obtain characteristic data");
return;
}
- for (l = characteristics; l; l = l->next) {
- struct gatt_char *c = l->data;
- struct characteristic *ch;
+ if (bt_uuid_cmp(&pnpid_uuid, &uuid) == 0)
+ handle_pnpid(device, value_handle);
+ else {
+ char uuid_str[MAX_LEN_UUID_STR];
- ch = g_new0(struct characteristic, 1);
- ch->attr.handle = c->handle;
- ch->attr.properties = c->properties;
- ch->attr.value_handle = c->value_handle;
- memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
- ch->d = d;
-
- d->chars = g_slist_append(d->chars, ch);
-
- process_deviceinfo_char(ch);
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+ DBG("Unsupported characteristic: %s", uuid_str);
}
}
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
- struct deviceinfo *d = user_data;
- d->attrib = g_attrib_ref(attrib);
+static void foreach_deviceinfo_service(struct gatt_db_attribute *attr,
+ void *user_data)
+{
+ struct btd_device *device = user_data;
- gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
- NULL, configure_deviceinfo_cb, d);
+ gatt_db_service_foreach_char(attr, handle_characteristic, device);
}
-static void attio_disconnected_cb(gpointer user_data)
+static int deviceinfo_driver_probe(struct btd_service *service)
{
- struct deviceinfo *d = user_data;
-
- g_attrib_unref(d->attrib);
- d->attrib = NULL;
+ return 0;
}
-static int deviceinfo_register(struct btd_service *service,
- struct gatt_primary *prim)
+static void deviceinfo_driver_remove(struct btd_service *service)
{
- struct btd_device *device = btd_service_get_device(service);
- struct deviceinfo *d;
-
- d = g_new0(struct deviceinfo, 1);
- d->dev = btd_device_ref(device);
- d->svc_range = g_new0(struct att_range, 1);
- d->svc_range->start = prim->range.start;
- d->svc_range->end = prim->range.end;
-
- btd_service_set_user_data(service, d);
-
- d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
- attio_disconnected_cb, d);
- return 0;
}
-static int deviceinfo_driver_probe(struct btd_service *service)
+
+static int deviceinfo_driver_accept(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
- struct gatt_primary *prim;
+ struct gatt_db *db = btd_device_get_gatt_db(device);
+ char addr[18];
+ bt_uuid_t deviceinfo_uuid;
- prim = btd_device_get_primary(device, DEVICE_INFORMATION_UUID);
- if (prim == NULL)
- return -EINVAL;
+ ba2str(device_get_address(device), addr);
+ DBG("deviceinfo profile accept (%s)", addr);
- return deviceinfo_register(service, prim);
+ /* Handle the device info service */
+ bt_string_to_uuid(&deviceinfo_uuid, DEVICE_INFORMATION_UUID);
+ gatt_db_foreach_service(db, &deviceinfo_uuid,
+ foreach_deviceinfo_service, device);
+
+ return 0;
}
static struct btd_profile deviceinfo_profile = {
.name = "deviceinfo",
.remote_uuid = DEVICE_INFORMATION_UUID,
+ .external = true,
.device_probe = deviceinfo_driver_probe,
- .device_remove = deviceinfo_driver_remove
+ .device_remove = deviceinfo_driver_remove,
+ .accept = deviceinfo_driver_accept,
};
static int deviceinfo_init(void)
diff --git a/profiles/deviceinfo/dis.c b/profiles/deviceinfo/dis.c
new file mode 100644
index 00000000..91c5d392
--- /dev/null
+++ b/profiles/deviceinfo/dis.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "src/log.h"
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+
+#include "profiles/deviceinfo/dis.h"
+
+#define PNP_ID_SIZE 7
+
+struct bt_dis {
+ int ref_count;
+ uint16_t handle;
+ uint8_t source;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+ GAttrib *attrib; /* GATT connection */
+ struct gatt_primary *primary; /* Primary details */
+ bt_dis_notify notify;
+ void *notify_data;
+ struct queue *gatt_op;
+};
+
+struct characteristic {
+ struct gatt_char attr; /* Characteristic */
+ struct bt_dis *d; /* deviceinfo where the char belongs */
+};
+
+struct gatt_request {
+ unsigned int id;
+ struct bt_dis *dis;
+ void *user_data;
+};
+
+static void destroy_gatt_req(struct gatt_request *req)
+{
+ queue_remove(req->dis->gatt_op, req);
+ bt_dis_unref(req->dis);
+ free(req);
+}
+
+static void dis_free(struct bt_dis *dis)
+{
+ bt_dis_detach(dis);
+
+ g_free(dis->primary);
+ queue_destroy(dis->gatt_op, (void *) destroy_gatt_req);
+ g_free(dis);
+}
+
+struct bt_dis *bt_dis_new(void *primary)
+{
+ struct bt_dis *dis;
+
+ dis = g_try_new0(struct bt_dis, 1);
+ if (!dis)
+ return NULL;
+
+ dis->gatt_op = queue_new();
+
+ if (primary)
+ dis->primary = g_memdup(primary, sizeof(*dis->primary));
+
+ return bt_dis_ref(dis);
+}
+
+struct bt_dis *bt_dis_ref(struct bt_dis *dis)
+{
+ if (!dis)
+ return NULL;
+
+ __sync_fetch_and_add(&dis->ref_count, 1);
+
+ return dis;
+}
+
+void bt_dis_unref(struct bt_dis *dis)
+{
+ if (!dis)
+ return;
+
+ if (__sync_sub_and_fetch(&dis->ref_count, 1))
+ return;
+
+ dis_free(dis);
+}
+
+static struct gatt_request *create_request(struct bt_dis *dis,
+ void *user_data)
+{
+ struct gatt_request *req;
+
+ req = new0(struct gatt_request, 1);
+ req->user_data = user_data;
+ req->dis = bt_dis_ref(dis);
+
+ return req;
+}
+
+static bool set_and_store_gatt_req(struct bt_dis *dis,
+ struct gatt_request *req,
+ unsigned int id)
+{
+ req->id = id;
+ return queue_push_head(dis->gatt_op, req);
+}
+
+static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_dis *dis = req->user_data;
+ uint8_t value[PNP_ID_SIZE];
+ ssize_t vlen;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Error reading PNP_ID value: %s", att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ error("Error reading PNP_ID: Protocol error");
+ return;
+ }
+
+ if (vlen < 7) {
+ error("Error reading PNP_ID: Invalid pdu length received");
+ return;
+ }
+
+ dis->source = value[0];
+ dis->vendor = get_le16(&value[1]);
+ dis->product = get_le16(&value[3]);
+ dis->version = get_le16(&value[5]);
+
+ DBG("source: 0x%02X vendor: 0x%04X product: 0x%04X version: 0x%04X",
+ dis->source, dis->vendor, dis->product, dis->version);
+
+ if (dis->notify)
+ dis->notify(dis->source, dis->vendor, dis->product,
+ dis->version, dis->notify_data);
+}
+
+static void read_char(struct bt_dis *dis, GAttrib *attrib, uint16_t handle,
+ GAttribResultFunc func, gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(dis, user_data);
+
+ id = gatt_read_char(attrib, handle, func, req);
+
+ if (set_and_store_gatt_req(dis, req, id))
+ return;
+
+ error("dis: Could not read characteristic");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void discover_char(struct bt_dis *dis, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(dis, user_data);
+
+ id = gatt_discover_char(attrib, start, end, uuid, func, req);
+
+ if (set_and_store_gatt_req(dis, req, id))
+ return;
+
+ error("dis: Could not send discover characteristic");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
+ void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_dis *d = req->user_data;
+ GSList *l;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Discover deviceinfo characteristics: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for (l = characteristics; l; l = l->next) {
+ struct gatt_char *c = l->data;
+
+ if (strcmp(c->uuid, PNPID_UUID) == 0) {
+ d->handle = c->value_handle;
+ read_char(d, d->attrib, d->handle, read_pnpid_cb, d);
+ break;
+ }
+ }
+}
+
+bool bt_dis_attach(struct bt_dis *dis, void *attrib)
+{
+ struct gatt_primary *primary = dis->primary;
+
+ if (dis->attrib || !primary)
+ return false;
+
+ dis->attrib = g_attrib_ref(attrib);
+
+ if (!dis->handle)
+ discover_char(dis, dis->attrib, primary->range.start,
+ primary->range.end, NULL,
+ configure_deviceinfo_cb, dis);
+
+ return true;
+}
+
+static void cancel_gatt_req(struct gatt_request *req)
+{
+ if (g_attrib_cancel(req->dis->attrib, req->id))
+ destroy_gatt_req(req);
+}
+
+void bt_dis_detach(struct bt_dis *dis)
+{
+ if (!dis->attrib)
+ return;
+
+ queue_foreach(dis->gatt_op, (void *) cancel_gatt_req, NULL);
+ g_attrib_unref(dis->attrib);
+ dis->attrib = NULL;
+}
+
+bool bt_dis_set_notification(struct bt_dis *dis, bt_dis_notify func,
+ void *user_data)
+{
+ if (!dis)
+ return false;
+
+ dis->notify = func;
+ dis->notify_data = user_data;
+
+ return true;
+}
diff --git a/profiles/deviceinfo/dis.h b/profiles/deviceinfo/dis.h
new file mode 100644
index 00000000..faf27b3d
--- /dev/null
+++ b/profiles/deviceinfo/dis.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bt_dis;
+
+struct bt_dis *bt_dis_new(void *primary);
+
+struct bt_dis *bt_dis_ref(struct bt_dis *dis);
+void bt_dis_unref(struct bt_dis *dis);
+
+bool bt_dis_attach(struct bt_dis *dis, void *gatt);
+void bt_dis_detach(struct bt_dis *dis);
+
+typedef void (*bt_dis_notify) (uint8_t source, uint16_t vendor,
+ uint16_t product, uint16_t version,
+ void *user_data);
+
+bool bt_dis_set_notification(struct bt_dis *dis, bt_dis_notify func,
+ void *user_data);
diff --git a/profiles/gap/gas.c b/profiles/gap/gas.c
index 09aa832e..35e47530 100644
--- a/profiles/gap/gas.c
+++ b/profiles/gap/gas.c
@@ -53,7 +53,6 @@
struct gas {
struct btd_device *device;
struct gatt_db *db;
- unsigned int db_id;
struct bt_gatt_client *client;
struct gatt_db_attribute *attr;
};
@@ -62,7 +61,6 @@ static GSList *devices;
static void gas_free(struct gas *gas)
{
- gatt_db_unregister(gas->db, gas->db_id);
gatt_db_unref(gas->db);
bt_gatt_client_unref(gas->client);
btd_device_unref(gas->device);
@@ -307,43 +305,6 @@ static void foreach_gap_service(struct gatt_db_attribute *attr, void *user_data)
handle_gap_service(gas);
}
-static void service_added(struct gatt_db_attribute *attr, void *user_data)
-{
- struct gas *gas = user_data;
- bt_uuid_t uuid, gap_uuid;
-
- if (!bt_gatt_client_is_ready(gas->client))
- return;
-
- gatt_db_attribute_get_service_uuid(attr, &uuid);
- bt_uuid16_create(&gap_uuid, GAP_UUID16);
-
- if (bt_uuid_cmp(&uuid, &gap_uuid))
- return;
-
- if (gas->attr) {
- error("More than one GAP service added to device");
- return;
- }
-
- DBG("GAP service added");
-
- gas->attr = attr;
- handle_gap_service(gas);
-}
-
-static void service_removed(struct gatt_db_attribute *attr, void *user_data)
-{
- struct gas *gas = user_data;
-
- if (gas->attr != attr)
- return;
-
- DBG("GAP service removed");
-
- gas->attr = NULL;
-}
-
static int gap_driver_accept(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
@@ -367,14 +328,11 @@ static int gap_driver_accept(struct btd_service *service)
/* Clean-up any old client/db and acquire the new ones */
gas->attr = NULL;
- gatt_db_unregister(gas->db, gas->db_id);
gatt_db_unref(gas->db);
bt_gatt_client_unref(gas->client);
gas->db = gatt_db_ref(db);
gas->client = bt_gatt_client_ref(client);
- gas->db_id = gatt_db_register(db, service_added, service_removed, gas,
- NULL);
/* Handle the GAP services */
bt_uuid16_create(&gap_uuid, GAP_UUID16);
diff --git a/profiles/input/hog-lib.c b/profiles/input/hog-lib.c
new file mode 100644
index 00000000..1df1799b
--- /dev/null
+++ b/profiles/input/hog-lib.c
@@ -0,0 +1,1550 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation.
+ * Copyright (C) 2012 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2012 Nordic Semiconductor Inc.
+ * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/shared/util.h"
+#include "src/shared/uhid.h"
+#include "src/shared/queue.h"
+#include "src/log.h"
+
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
+
+#include "btio/btio.h"
+
+#include "profiles/scanparam/scpp.h"
+#include "profiles/deviceinfo/dis.h"
+#include "profiles/battery/bas.h"
+#include "profiles/input/hog-lib.h"
+
+#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
+
+#define HOG_INFO_UUID 0x2A4A
+#define HOG_REPORT_MAP_UUID 0x2A4B
+#define HOG_REPORT_UUID 0x2A4D
+#define HOG_PROTO_MODE_UUID 0x2A4E
+#define HOG_CONTROL_POINT_UUID 0x2A4C
+
+#define HOG_REPORT_TYPE_INPUT 1
+#define HOG_REPORT_TYPE_OUTPUT 2
+#define HOG_REPORT_TYPE_FEATURE 3
+
+#define HOG_PROTO_MODE_BOOT 0
+#define HOG_PROTO_MODE_REPORT 1
+
+#define HOG_REPORT_MAP_MAX_SIZE 512
+#define HID_INFO_SIZE 4
+#define ATT_NOTIFICATION_HEADER_SIZE 3
+
+struct bt_hog {
+ int ref_count;
+ char *name;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+ struct gatt_primary *primary;
+ GAttrib *attrib;
+ GSList *reports;
+ struct bt_uhid *uhid;
+ int uhid_fd;
+ bool uhid_created;
+ gboolean has_report_id;
+ uint16_t bcdhid;
+ uint8_t bcountrycode;
+ uint16_t proto_mode_handle;
+ uint16_t ctrlpt_handle;
+ uint8_t flags;
+ unsigned int getrep_att;
+ uint16_t getrep_id;
+ unsigned int setrep_att;
+ uint16_t setrep_id;
+ struct bt_scpp *scpp;
+ struct bt_dis *dis;
+ struct queue *bas;
+ GSList *instances;
+ struct queue *gatt_op;
+};
+
+struct report {
+ struct bt_hog *hog;
+ uint8_t id;
+ uint8_t type;
+ uint16_t ccc_handle;
+ guint notifyid;
+ struct gatt_char *decl;
+ uint16_t len;
+ uint8_t *value;
+};
+
+struct gatt_request {
+ unsigned int id;
+ struct bt_hog *hog;
+ void *user_data;
+};
+
+static struct gatt_request *create_request(struct bt_hog *hog,
+ void *user_data)
+{
+ struct gatt_request *req;
+
+ req = new0(struct gatt_request, 1);
+ if (!req)
+ return NULL;
+
+ req->user_data = user_data;
+ req->hog = bt_hog_ref(hog);
+
+ return req;
+}
+
+static bool set_and_store_gatt_req(struct bt_hog *hog,
+ struct gatt_request *req,
+ unsigned int id)
+{
+ req->id = id;
+ return queue_push_head(hog->gatt_op, req);
+}
+
+static void destroy_gatt_req(struct gatt_request *req)
+{
+ queue_remove(req->hog->gatt_op, req);
+ bt_hog_unref(req->hog);
+ free(req);
+}
+
+static void write_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,
+ const uint8_t *value, size_t vlen,
+ GAttribResultFunc func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(hog, user_data);
+ if (!req)
+ return;
+
+ id = gatt_write_char(attrib, handle, value, vlen, func, req);
+
+ if (set_and_store_gatt_req(hog, req, id))
+ return;
+
+ error("hog: Could not read char");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void read_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,
+ GAttribResultFunc func, gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(hog, user_data);
+ if (!req)
+ return;
+
+ id = gatt_read_char(attrib, handle, func, req);
+
+ if (set_and_store_gatt_req(hog, req, id))
+ return;
+
+ error("hog: Could not read char");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void discover_desc(struct bt_hog *hog, GAttrib *attrib,
+ uint16_t start, uint16_t end, gatt_cb_t func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(hog, user_data);
+ if (!req)
+ return;
+
+ id = gatt_discover_desc(attrib, start, end, NULL, func, req);
+ if (set_and_store_gatt_req(hog, req, id))
+ return;
+
+ error("hog: Could not discover descriptors");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void discover_char(struct bt_hog *hog, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(hog, user_data);
+ if (!req)
+ return;
+
+ id = gatt_discover_char(attrib, start, end, uuid, func, req);
+
+ if (set_and_store_gatt_req(hog, req, id))
+ return;
+
+ error("hog: Could not discover characteristic");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void discover_primary(struct bt_hog *hog, GAttrib *attrib,
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(hog, user_data);
+ if (!req)
+ return;
+
+ id = gatt_discover_primary(attrib, uuid, func, req);
+
+ if (set_and_store_gatt_req(hog, req, id))
+ return;
+
+ error("hog: Could not send discover primary");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void find_included(struct bt_hog *hog, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ gatt_cb_t func, gpointer user_data)
+{
+ struct gatt_request *req;
+ unsigned int id;
+
+ req = create_request(hog, user_data);
+ if (!req)
+ return;
+
+ id = gatt_find_included(attrib, start, end, func, req);
+
+ if (set_and_store_gatt_req(hog, req, id))
+ return;
+
+ error("Could not find included");
+ g_attrib_cancel(attrib, id);
+ free(req);
+}
+
+static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
+{
+ struct report *report = user_data;
+ struct bt_hog *hog = report->hog;
+ struct uhid_event ev;
+ uint8_t *buf;
+ int err;
+
+ if (len < ATT_NOTIFICATION_HEADER_SIZE) {
+ error("Malformed ATT notification");
+ return;
+ }
+
+ pdu += ATT_NOTIFICATION_HEADER_SIZE;
+ len -= ATT_NOTIFICATION_HEADER_SIZE;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_INPUT;
+ buf = ev.u.input.data;
+
+ if (hog->has_report_id) {
+ buf[0] = report->id;
+ len = MIN(len, sizeof(ev.u.input.data) - 1);
+ memcpy(buf + 1, pdu, len);
+ ev.u.input.size = ++len;
+ } else {
+ len = MIN(len, sizeof(ev.u.input.data));
+ memcpy(buf, pdu, len);
+ ev.u.input.size = len;
+ }
+
+ err = bt_uhid_send(hog->uhid, &ev);
+ if (err < 0) {
+ error("bt_uhid_send: %s (%d)", strerror(-err), -err);
+ return;
+ }
+
+ DBG("HoG report (%u bytes)", ev.u.input.size);
+}
+
+static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct report *report = req->user_data;
+ struct bt_hog *hog = report->hog;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Write report characteristic descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ report->notifyid = g_attrib_register(hog->attrib,
+ ATT_OP_HANDLE_NOTIFY,
+ report->decl->value_handle,
+ report_value_cb, report, NULL);
+
+ DBG("Report characteristic descriptor written: notifications enabled");
+}
+
+static void write_ccc(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,
+ void *user_data)
+{
+ uint8_t value[2];
+
+ put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+
+ write_char(hog, attrib, handle, value, sizeof(value),
+ report_ccc_written_cb, user_data);
+}
+
+static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct report *report = req->user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Error reading CCC value: %s", att_ecode2str(status));
+ return;
+ }
+
+ write_ccc(report->hog, report->hog->attrib, report->ccc_handle, report);
+}
+
+static const char *type_to_string(uint8_t type)
+{
+ switch (type) {
+ case HOG_REPORT_TYPE_INPUT:
+ return "input";
+ case HOG_REPORT_TYPE_OUTPUT:
+ return "output";
+ case HOG_REPORT_TYPE_FEATURE:
+ return "feature";
+ }
+
+ return NULL;
+}
+
+static void report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct report *report = req->user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Read Report Reference descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (plen != 3) {
+ error("Malformed ATT read response");
+ return;
+ }
+
+ report->id = pdu[1];
+ report->type = pdu[2];
+
+ DBG("Report 0x%04x: id 0x%02x type %s", report->decl->value_handle,
+ report->id, type_to_string(report->type));
+
+ /* Enable notifications only for Input Reports */
+ if (report->type == HOG_REPORT_TYPE_INPUT)
+ read_char(report->hog, report->hog->attrib, report->ccc_handle,
+ ccc_read_cb, report);
+}
+
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data);
+
+static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Discover external descriptors failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for ( ; descs; descs = descs->next) {
+ struct gatt_desc *desc = descs->data;
+
+ read_char(hog, hog->attrib, desc->handle,
+ external_report_reference_cb,
+ hog);
+ }
+}
+
+static void discover_external(struct bt_hog *hog, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ gpointer user_data)
+{
+ bt_uuid_t uuid;
+
+ if (start > end)
+ return;
+
+ bt_uuid16_create(&uuid, GATT_EXTERNAL_REPORT_REFERENCE);
+
+ discover_desc(hog, attrib, start, end, discover_external_cb,
+ user_data);
+}
+
+static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct report *report = req->user_data;
+ struct bt_hog *hog = report->hog;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Discover report descriptors failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for ( ; descs; descs = descs->next) {
+ struct gatt_desc *desc = descs->data;
+
+ switch (desc->uuid16) {
+ case GATT_CLIENT_CHARAC_CFG_UUID:
+ report->ccc_handle = desc->handle;
+ break;
+ case GATT_REPORT_REFERENCE:
+ read_char(hog, hog->attrib, desc->handle,
+ report_reference_cb, report);
+ break;
+ }
+ }
+}
+
+static void discover_report(struct bt_hog *hog, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ gpointer user_data)
+{
+ if (start > end)
+ return;
+
+ discover_desc(hog, attrib, start, end, discover_report_cb, user_data);
+}
+
+static void report_read_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct report *report = req->user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Error reading Report value: %s", att_ecode2str(status));
+ return;
+ }
+
+ if (report->value)
+ g_free(report->value);
+
+ report->value = g_memdup(pdu, len);
+ report->len = len;
+}
+
+static int report_chrc_cmp(const void *data, const void *user_data)
+{
+ const struct report *report = data;
+ const struct gatt_char *decl = user_data;
+
+ return report->decl->handle - decl->handle;
+}
+
+static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
+{
+ struct report *report;
+ GSList *l;
+
+ /* Skip if report already exists */
+ l = g_slist_find_custom(hog->reports, chr, report_chrc_cmp);
+ if (l)
+ return l->data;
+
+ report = g_new0(struct report, 1);
+ report->hog = hog;
+ report->decl = g_memdup(chr, sizeof(*chr));
+ hog->reports = g_slist_append(hog->reports, report);
+
+ read_char(hog, hog->attrib, chr->value_handle, report_read_cb, report);
+
+ return report;
+}
+
+static void external_service_char_cb(uint8_t status, GSList *chars,
+ void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ struct gatt_primary *primary = hog->primary;
+ struct report *report;
+ GSList *l;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ const char *str = att_ecode2str(status);
+ DBG("Discover external service characteristic failed: %s", str);
+ return;
+ }
+
+ for (l = chars; l; l = g_slist_next(l)) {
+ struct gatt_char *chr, *next;
+ uint16_t start, end;
+
+ chr = l->data;
+ next = l->next ? l->next->data : NULL;
+
+ DBG("0x%04x UUID: %s properties: %02x",
+ chr->handle, chr->uuid, chr->properties);
+
+ report = report_new(hog, chr);
+ start = chr->value_handle + 1;
+ end = (next ? next->handle - 1 : primary->range.end);
+ discover_report(hog, hog->attrib, start, end, report);
+ }
+}
+
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ uint16_t uuid16;
+ bt_uuid_t uuid;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Read External Report Reference descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (plen != 3) {
+ error("Malformed ATT read response");
+ return;
+ }
+
+ uuid16 = get_le16(&pdu[1]);
+ DBG("External report reference read, external report characteristic "
+ "UUID: 0x%04x", uuid16);
+
+ /* Do not discover if is not a Report */
+ if (uuid16 != HOG_REPORT_UUID)
+ return;
+
+ bt_uuid16_create(&uuid, uuid16);
+ discover_char(hog, hog->attrib, 0x0001, 0xffff, &uuid,
+ external_service_char_cb, hog);
+}
+
+static int report_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct report *ra = a, *rb = b;
+
+ /* sort by type first.. */
+ if (ra->type != rb->type)
+ return ra->type - rb->type;
+
+ /* skip id check in case of report id 0 */
+ if (!rb->id)
+ return 0;
+
+ /* ..then by id */
+ return ra->id - rb->id;
+}
+
+static struct report *find_report(struct bt_hog *hog, uint8_t type, uint8_t id)
+{
+ struct report cmp;
+ GSList *l;
+
+ cmp.type = type;
+ cmp.id = hog->has_report_id ? id : 0;
+
+ l = g_slist_find_custom(hog->reports, &cmp, report_cmp);
+
+ return l ? l->data : NULL;
+}
+
+static struct report *find_report_by_rtype(struct bt_hog *hog, uint8_t rtype,
+ uint8_t id)
+{
+ uint8_t type;
+
+ switch (rtype) {
+ case UHID_FEATURE_REPORT:
+ type = HOG_REPORT_TYPE_FEATURE;
+ break;
+ case UHID_OUTPUT_REPORT:
+ type = HOG_REPORT_TYPE_OUTPUT;
+ break;
+ case UHID_INPUT_REPORT:
+ type = HOG_REPORT_TYPE_INPUT;
+ break;
+ default:
+ return NULL;
+ }
+
+ return find_report(hog, type, id);
+}
+
+static void output_written_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Write output report failed: %s", att_ecode2str(status));
+ return;
+ }
+}
+
+static void forward_report(struct uhid_event *ev, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct report *report;
+ void *data;
+ int size;
+
+ report = find_report_by_rtype(hog, ev->u.output.rtype,
+ ev->u.output.data[0]);
+ if (!report)
+ return;
+
+ data = ev->u.output.data;
+ size = ev->u.output.size;
+ if (hog->has_report_id && size > 0) {
+ data++;
+ --size;
+ }
+
+ DBG("Sending report type %d ID %d to handle 0x%X", report->type,
+ report->id, report->decl->value_handle);
+
+ if (hog->attrib == NULL)
+ return;
+
+ if (report->decl->properties & GATT_CHR_PROP_WRITE)
+ write_char(hog, hog->attrib, report->decl->value_handle,
+ data, size, output_written_cb, hog);
+ else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
+ gatt_write_cmd(hog->attrib, report->decl->value_handle,
+ data, size, NULL, NULL);
+}
+
+static void get_feature(struct uhid_event *ev, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct report *report;
+ struct uhid_event rsp;
+ int err;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.type = UHID_FEATURE_ANSWER;
+ rsp.u.feature_answer.id = ev->u.feature.id;
+
+ report = find_report_by_rtype(hog, ev->u.feature.rtype,
+ ev->u.feature.rnum);
+ if (!report) {
+ rsp.u.feature_answer.err = ENOTSUP;
+ goto done;
+ }
+
+ if (!report->value) {
+ rsp.u.feature_answer.err = EIO;
+ goto done;
+ }
+
+ rsp.u.feature_answer.size = report->len;
+ memcpy(rsp.u.feature_answer.data, report->value, report->len);
+
+done:
+ err = bt_uhid_send(hog->uhid, &rsp);
+ if (err < 0)
+ error("bt_uhid_send: %s", strerror(-err));
+}
+
+static void set_report_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct uhid_event rsp;
+ int err;
+
+ hog->setrep_att = 0;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.type = UHID_SET_REPORT_REPLY;
+ rsp.u.set_report_reply.id = hog->setrep_id;
+ rsp.u.set_report_reply.err = status;
+
+ if (status != 0)
+ error("Error setting Report value: %s", att_ecode2str(status));
+
+ err = bt_uhid_send(hog->uhid, &rsp);
+ if (err < 0)
+ error("bt_uhid_send: %s", strerror(-err));
+}
+
+static void set_report(struct uhid_event *ev, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct report *report;
+ void *data;
+ int size;
+ int err;
+
+ /* uhid never sends reqs in parallel; if there's a req, it timed out */
+ if (hog->setrep_att) {
+ g_attrib_cancel(hog->attrib, hog->setrep_att);
+ hog->setrep_att = 0;
+ }
+
+ hog->setrep_id = ev->u.set_report.id;
+
+ report = find_report_by_rtype(hog, ev->u.set_report.rtype,
+ ev->u.set_report.rnum);
+ if (!report) {
+ err = ENOTSUP;
+ goto fail;
+ }
+
+ data = ev->u.set_report.data;
+ size = ev->u.set_report.size;
+ if (hog->has_report_id && size > 0) {
+ data++;
+ --size;
+ }
+
+ DBG("Sending report type %d ID %d to handle 0x%X", report->type,
+ report->id, report->decl->value_handle);
+
+ if (hog->attrib == NULL)
+ return;
+
+ hog->setrep_att = gatt_write_char(hog->attrib,
+ report->decl->value_handle,
+ data, size, set_report_cb,
+ hog);
+ if (!hog->setrep_att) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ return;
+fail:
+ /* cancel the request on failure */
+ set_report_cb(err, NULL, 0, hog);
+}
+
+static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct uhid_event rsp;
+ int err;
+
+ hog->getrep_att = 0;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.type = UHID_GET_REPORT_REPLY;
+ rsp.u.get_report_reply.id = hog->getrep_id;
+
+ if (status != 0) {
+ error("Error reading Report value: %s", att_ecode2str(status));
+ goto exit;
+ }
+
+ if (len == 0) {
+ error("Error reading Report, length %d", len);
+ status = EIO;
+ goto exit;
+ }
+
+ if (pdu[0] != 0x0b) {
+ error("Error reading Report, invalid response: %02x", pdu[0]);
+ status = EPROTO;
+ goto exit;
+ }
+
+ --len;
+ ++pdu;
+ if (hog->has_report_id && len > 0) {
+ --len;
+ ++pdu;
+ }
+
+ rsp.u.get_report_reply.size = len;
+ memcpy(rsp.u.get_report_reply.data, pdu, len);
+
+exit:
+ rsp.u.get_report_reply.err = status;
+ err = bt_uhid_send(hog->uhid, &rsp);
+ if (err < 0)
+ error("bt_uhid_send: %s", strerror(-err));
+}
+
+static void get_report(struct uhid_event *ev, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct report *report;
+ guint8 err;
+
+ /* uhid never sends reqs in parallel; if there's a req, it timed out */
+ if (hog->getrep_att) {
+ g_attrib_cancel(hog->attrib, hog->getrep_att);
+ hog->getrep_att = 0;
+ }
+
+ hog->getrep_id = ev->u.get_report.id;
+
+ report = find_report_by_rtype(hog, ev->u.get_report.rtype,
+ ev->u.get_report.rnum);
+ if (!report) {
+ err = ENOTSUP;
+ goto fail;
+ }
+
+ hog->getrep_att = gatt_read_char(hog->attrib,
+ report->decl->value_handle,
+ get_report_cb, hog);
+ if (!hog->getrep_att) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ return;
+
+fail:
+ /* cancel the request on failure */
+ get_report_cb(err, NULL, 0, hog);
+}
+
+static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
+ bool *is_long)
+{
+ if (!blen)
+ return false;
+
+ *is_long = (buf[0] == 0xfe);
+
+ if (*is_long) {
+ if (blen < 3)
+ return false;
+
+ /*
+ * long item:
+ * byte 0 -> 0xFE
+ * byte 1 -> data size
+ * byte 2 -> tag
+ * + data
+ */
+
+ *len = buf[1] + 3;
+ } else {
+ uint8_t b_size;
+
+ /*
+ * short item:
+ * byte 0[1..0] -> data size (=0, 1, 2, 4)
+ * byte 0[3..2] -> type
+ * byte 0[7..4] -> tag
+ * + data
+ */
+
+ b_size = buf[0] & 0x03;
+ *len = (b_size ? 1 << (b_size - 1) : 0) + 1;
+ }
+
+ /* item length should be no more than input buffer length */
+ return *len <= blen;
+}
+
+static char *item2string(char *str, uint8_t *buf, uint8_t len)
+{
+ char *p = str;
+ int i;
+
+ /*
+ * Since long item tags are not defined except for vendor ones, we
+ * just ensure that short items are printed properly (up to 5 bytes).
+ */
+ for (i = 0; i < 6 && i < len; i++)
+ p += sprintf(p, " %02x", buf[i]);
+
+ /*
+ * If there are some data left, just add continuation mark to indicate
+ * this.
+ */
+ if (i < len)
+ sprintf(p, " ...");
+
+ return str;
+}
+
+static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
+ struct uhid_event ev;
+ ssize_t vlen;
+ char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
+ int i, err;
+ GError *gerr = NULL;
+
+ destroy_gatt_req(req);
+
+ DBG("HoG inspecting report map");
+
+ if (status != 0) {
+ error("Report Map read failed: %s", att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+ if (vlen < 0) {
+ error("ATT protocol error");
+ return;
+ }
+
+ DBG("Report MAP:");
+ for (i = 0; i < vlen;) {
+ ssize_t ilen = 0;
+ bool long_item = false;
+
+ if (get_descriptor_item_info(&value[i], vlen - i, &ilen,
+ &long_item)) {
+ /* Report ID is short item with prefix 100001xx */
+ if (!long_item && (value[i] & 0xfc) == 0x84)
+ hog->has_report_id = TRUE;
+
+ DBG("\t%s", item2string(itemstr, &value[i], ilen));
+
+ i += ilen;
+ } else {
+ error("Report Map parsing failed at %d", i);
+
+ /* Just print remaining items at once and break */
+ DBG("\t%s", item2string(itemstr, &value[i], vlen - i));
+ break;
+ }
+ }
+
+ /* create uHID device */
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+
+ bt_io_get(g_attrib_get_channel(hog->attrib), &gerr,
+ BT_IO_OPT_SOURCE, ev.u.create.phys,
+ BT_IO_OPT_DEST, ev.u.create.uniq,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("Failed to connection details: %s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ strcpy((char *) ev.u.create.name, hog->name);
+ ev.u.create.vendor = hog->vendor;
+ ev.u.create.product = hog->product;
+ ev.u.create.version = hog->version;
+ ev.u.create.country = hog->bcountrycode;
+ ev.u.create.bus = BUS_BLUETOOTH;
+ ev.u.create.rd_data = value;
+ ev.u.create.rd_size = vlen;
+
+ err = bt_uhid_send(hog->uhid, &ev);
+ if (err < 0) {
+ error("bt_uhid_send: %s", strerror(-err));
+ return;
+ }
+
+ bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog);
+ bt_uhid_register(hog->uhid, UHID_FEATURE, get_feature, hog);
+ bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog);
+ bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog);
+
+ hog->uhid_created = true;
+
+ DBG("HoG created uHID device");
+}
+
+static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ uint8_t value[HID_INFO_SIZE];
+ ssize_t vlen;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("HID Information read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+ if (vlen != 4) {
+ error("ATT protocol error");
+ return;
+ }
+
+ hog->bcdhid = get_le16(&value[0]);
+ hog->bcountrycode = value[2];
+ hog->flags = value[3];
+
+ DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X",
+ hog->bcdhid, hog->bcountrycode, hog->flags);
+}
+
+static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ uint8_t value;
+ ssize_t vlen;
+
+ destroy_gatt_req(req);
+
+ if (status != 0) {
+ error("Protocol Mode characteristic read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, plen, &value, sizeof(value));
+ if (vlen < 0) {
+ error("ATT protocol error");
+ return;
+ }
+
+ if (value == HOG_PROTO_MODE_BOOT) {
+ uint8_t nval = HOG_PROTO_MODE_REPORT;
+
+ DBG("HoG is operating in Boot Procotol Mode");
+
+ gatt_write_cmd(hog->attrib, hog->proto_mode_handle, &nval,
+ sizeof(nval), NULL, NULL);
+ } else if (value == HOG_PROTO_MODE_REPORT)
+ DBG("HoG is operating in Report Protocol Mode");
+}
+
+static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ struct gatt_primary *primary = hog->primary;
+ bt_uuid_t report_uuid, report_map_uuid, info_uuid;
+ bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
+ struct report *report;
+ GSList *l;
+ uint16_t info_handle = 0, proto_mode_handle = 0;
+
+ destroy_gatt_req(req);
+
+ DBG("HoG inspecting characteristics");
+
+ if (status != 0) {
+ const char *str = att_ecode2str(status);
+ DBG("Discover all characteristics failed: %s", str);
+ return;
+ }
+
+ bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
+ bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
+ bt_uuid16_create(&info_uuid, HOG_INFO_UUID);
+ bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
+ bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
+
+ for (l = chars; l; l = g_slist_next(l)) {
+ struct gatt_char *chr, *next;
+ bt_uuid_t uuid;
+ uint16_t start, end;
+
+ chr = l->data;
+ next = l->next ? l->next->data : NULL;
+
+ DBG("0x%04x UUID: %s properties: %02x",
+ chr->handle, chr->uuid, chr->properties);
+
+ bt_string_to_uuid(&uuid, chr->uuid);
+
+ start = chr->value_handle + 1;
+ end = (next ? next->handle - 1 : primary->range.end);
+
+ if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
+ report = report_new(hog, chr);
+ discover_report(hog, hog->attrib, start, end, report);
+ } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
+ DBG("HoG discovering report map");
+ read_char(hog, hog->attrib, chr->value_handle,
+ report_map_read_cb, hog);
+ discover_external(hog, hog->attrib, start, end, hog);
+ } else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
+ info_handle = chr->value_handle;
+ else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
+ proto_mode_handle = chr->value_handle;
+ else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
+ hog->ctrlpt_handle = chr->value_handle;
+ }
+
+ if (proto_mode_handle) {
+ hog->proto_mode_handle = proto_mode_handle;
+ read_char(hog, hog->attrib, proto_mode_handle,
+ proto_mode_read_cb, hog);
+ }
+
+ if (info_handle)
+ read_char(hog, hog->attrib, info_handle, info_read_cb, hog);
+}
+
+static void report_free(void *data)
+{
+ struct report *report = data;
+
+ g_free(report->value);
+ g_free(report->decl);
+ g_free(report);
+}
+
+static void cancel_gatt_req(struct gatt_request *req)
+{
+ if (g_attrib_cancel(req->hog->attrib, req->id))
+ destroy_gatt_req(req);
+}
+
+static void hog_free(void *data)
+{
+ struct bt_hog *hog = data;
+
+ bt_hog_detach(hog);
+
+ queue_destroy(hog->bas, (void *) bt_bas_unref);
+ g_slist_free_full(hog->instances, hog_free);
+
+ bt_scpp_unref(hog->scpp);
+ bt_dis_unref(hog->dis);
+ bt_uhid_unref(hog->uhid);
+ g_slist_free_full(hog->reports, report_free);
+ g_free(hog->name);
+ g_free(hog->primary);
+ queue_destroy(hog->gatt_op, (void *) destroy_gatt_req);
+ g_free(hog);
+}
+
+struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
+ uint16_t product, uint16_t version,
+ void *primary)
+{
+ return bt_hog_new(-1, name, vendor, product, version, primary);
+}
+
+struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
+ uint16_t product, uint16_t version,
+ void *primary)
+{
+ struct bt_hog *hog;
+
+ hog = g_try_new0(struct bt_hog, 1);
+ if (!hog)
+ return NULL;
+
+ hog->gatt_op = queue_new();
+ hog->bas = queue_new();
+
+ if (fd < 0)
+ hog->uhid = bt_uhid_new_default();
+ else
+ hog->uhid = bt_uhid_new(fd);
+
+ hog->uhid_fd = fd;
+
+ if (!hog->gatt_op || !hog->bas || !hog->uhid) {
+ hog_free(hog);
+ return NULL;
+ }
+
+ hog->name = g_strdup(name);
+ hog->vendor = vendor;
+ hog->product = product;
+ hog->version = version;
+
+ if (primary)
+ hog->primary = g_memdup(primary, sizeof(*hog->primary));
+
+ return bt_hog_ref(hog);
+}
+
+struct bt_hog *bt_hog_ref(struct bt_hog *hog)
+{
+ if (!hog)
+ return NULL;
+
+ __sync_fetch_and_add(&hog->ref_count, 1);
+
+ return hog;
+}
+
+void bt_hog_unref(struct bt_hog *hog)
+{
+ if (!hog)
+ return;
+
+ if (__sync_sub_and_fetch(&hog->ref_count, 1))
+ return;
+
+ hog_free(hog);
+}
+
+static void find_included_cb(uint8_t status, GSList *services, void *user_data)
+{
+ struct gatt_request *req = user_data;
+ GSList *l;
+
+ DBG("");
+
+ destroy_gatt_req(req);
+
+ if (status) {
+ const char *str = att_ecode2str(status);
+ DBG("Find included failed: %s", str);
+ return;
+ }
+
+ for (l = services; l; l = l->next) {
+ struct gatt_included *include = l->data;
+
+ DBG("included: handle %x, uuid %s",
+ include->handle, include->uuid);
+ }
+}
+
+static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary)
+{
+ if (hog->scpp) {
+ bt_scpp_attach(hog->scpp, hog->attrib);
+ return;
+ }
+
+ hog->scpp = bt_scpp_new(primary);
+ if (hog->scpp)
+ bt_scpp_attach(hog->scpp, hog->attrib);
+}
+
+static void dis_notify(uint8_t source, uint16_t vendor, uint16_t product,
+ uint16_t version, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+
+ hog->vendor = vendor;
+ hog->product = product;
+ hog->version = version;
+}
+
+static void hog_attach_dis(struct bt_hog *hog, struct gatt_primary *primary)
+{
+ if (hog->dis) {
+ bt_dis_attach(hog->dis, hog->attrib);
+ return;
+ }
+
+ hog->dis = bt_dis_new(primary);
+ if (hog->dis) {
+ bt_dis_set_notification(hog->dis, dis_notify, hog);
+ bt_dis_attach(hog->dis, hog->attrib);
+ }
+}
+
+static void hog_attach_bas(struct bt_hog *hog, struct gatt_primary *primary)
+{
+ struct bt_bas *instance;
+
+ instance = bt_bas_new(primary);
+
+ bt_bas_attach(instance, hog->attrib);
+ queue_push_head(hog->bas, instance);
+}
+
+static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
+{
+ struct bt_hog *instance;
+
+ if (!hog->primary) {
+ hog->primary = g_memdup(primary, sizeof(*primary));
+ discover_char(hog, hog->attrib, primary->range.start,
+ primary->range.end, NULL,
+ char_discovered_cb, hog);
+ find_included(hog, hog->attrib, primary->range.start,
+ primary->range.end, find_included_cb, hog);
+ return;
+ }
+
+ instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
+ hog->product, hog->version, primary);
+ if (!instance)
+ return;
+
+ find_included(instance, hog->attrib, primary->range.start,
+ primary->range.end, find_included_cb, instance);
+
+ bt_hog_attach(instance, hog->attrib);
+ hog->instances = g_slist_append(hog->instances, instance);
+}
+
+static void primary_cb(uint8_t status, GSList *services, void *user_data)
+{
+ struct gatt_request *req = user_data;
+ struct bt_hog *hog = req->user_data;
+ struct gatt_primary *primary;
+ GSList *l;
+
+ DBG("");
+
+ destroy_gatt_req(req);
+
+ if (status) {
+ const char *str = att_ecode2str(status);
+ DBG("Discover primary failed: %s", str);
+ return;
+ }
+
+ if (!services) {
+ DBG("No primary service found");
+ return;
+ }
+
+ for (l = services; l; l = l->next) {
+ primary = l->data;
+
+ if (strcmp(primary->uuid, SCAN_PARAMETERS_UUID) == 0) {
+ hog_attach_scpp(hog, primary);
+ continue;
+ }
+
+ if (strcmp(primary->uuid, DEVICE_INFORMATION_UUID) == 0) {
+ hog_attach_dis(hog, primary);
+ continue;
+ }
+
+ if (strcmp(primary->uuid, BATTERY_UUID) == 0) {
+ hog_attach_bas(hog, primary);
+ continue;
+ }
+
+ if (strcmp(primary->uuid, HOG_UUID) == 0)
+ hog_attach_hog(hog, primary);
+ }
+}
+
+bool bt_hog_attach(struct bt_hog *hog, void *gatt)
+{
+ struct gatt_primary *primary = hog->primary;
+ GSList *l;
+
+ if (hog->attrib)
+ return false;
+
+ hog->attrib = g_attrib_ref(gatt);
+
+ if (!primary) {
+ discover_primary(hog, hog->attrib, NULL, primary_cb, hog);
+ return true;
+ }
+
+ if (hog->scpp)
+ bt_scpp_attach(hog->scpp, gatt);
+
+ if (hog->dis)
+ bt_dis_attach(hog->dis, gatt);
+
+ queue_foreach(hog->bas, (void *) bt_bas_attach, gatt);
+
+ for (l = hog->instances; l; l = l->next) {
+ struct bt_hog *instance = l->data;
+
+ bt_hog_attach(instance, gatt);
+ }
+
+ if (!hog->uhid_created) {
+ DBG("HoG discovering characteristics");
+ discover_char(hog, hog->attrib, primary->range.start,
+ primary->range.end, NULL,
+ char_discovered_cb, hog);
+ return true;
+ }
+
+ for (l = hog->reports; l; l = l->next) {
+ struct report *r = l->data;
+
+ r->notifyid = g_attrib_register(hog->attrib,
+ ATT_OP_HANDLE_NOTIFY,
+ r->decl->value_handle,
+ report_value_cb, r, NULL);
+ }
+
+ return true;
+}
+
+void bt_hog_detach(struct bt_hog *hog)
+{
+ GSList *l;
+
+ if (!hog->attrib)
+ return;
+
+ queue_foreach(hog->bas, (void *) bt_bas_detach, NULL);
+
+ for (l = hog->instances; l; l = l->next) {
+ struct bt_hog *instance = l->data;
+
+ bt_hog_detach(instance);
+ }
+
+ for (l = hog->reports; l; l = l->next) {
+ struct report *r = l->data;
+
+ if (r->notifyid > 0) {
+ g_attrib_unregister(hog->attrib, r->notifyid);
+ r->notifyid = 0;
+ }
+ }
+
+ if (hog->scpp)
+ bt_scpp_detach(hog->scpp);
+
+ if (hog->dis)
+ bt_dis_detach(hog->dis);
+
+ queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL);
+ g_attrib_unref(hog->attrib);
+ hog->attrib = NULL;
+}
+
+int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
+{
+ uint8_t value = suspend ? 0x00 : 0x01;
+
+ if (hog->attrib == NULL)
+ return -ENOTCONN;
+
+ if (hog->ctrlpt_handle == 0)
+ return -ENOTSUP;
+
+ gatt_write_cmd(hog->attrib, hog->ctrlpt_handle, &value,
+ sizeof(value), NULL, NULL);
+
+ return 0;
+}
+
+int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
+{
+ struct report *report;
+ GSList *l;
+
+ if (!hog)
+ return -EINVAL;
+
+ if (!hog->attrib)
+ return -ENOTCONN;
+
+ report = find_report(hog, type, 0);
+ if (!report)
+ return -ENOTSUP;
+
+ DBG("hog: Write report, handle 0x%X", report->decl->value_handle);
+
+ if (report->decl->properties & GATT_CHR_PROP_WRITE)
+ write_char(hog, hog->attrib, report->decl->value_handle,
+ data, size, output_written_cb, hog);
+
+ if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
+ gatt_write_cmd(hog->attrib, report->decl->value_handle,
+ data, size, NULL, NULL);
+
+ for (l = hog->instances; l; l = l->next) {
+ struct bt_hog *instance = l->data;
+
+ bt_hog_send_report(instance, data, size, type);
+ }
+
+ return 0;
+}
diff --git a/profiles/input/hog-lib.h b/profiles/input/hog-lib.h
new file mode 100644
index 00000000..2a9b899c
--- /dev/null
+++ b/profiles/input/hog-lib.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bt_hog;
+
+struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
+ uint16_t product, uint16_t version,
+ void *primary);
+
+struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
+ uint16_t product, uint16_t version,
+ void *primary);
+
+struct bt_hog *bt_hog_ref(struct bt_hog *hog);
+void bt_hog_unref(struct bt_hog *hog);
+
+bool bt_hog_attach(struct bt_hog *hog, void *gatt);
+void bt_hog_detach(struct bt_hog *hog);
+
+int bt_hog_set_control_point(struct bt_hog *hog, bool suspend);
+int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type);
diff --git a/profiles/input/hog.c b/profiles/input/hog.c
index 3d23d5b4..4dba83f7 100644
--- a/profiles/input/hog.c
+++ b/profiles/input/hog.c
@@ -48,6 +48,7 @@
#include "src/service.h"
#include "src/shared/util.h"
#include "src/shared/uhid.h"
+#include "src/shared/queue.h"
#include "src/plugin.h"
#include "suspend.h"
@@ -55,905 +56,99 @@
#include "attrib/gattrib.h"
#include "src/attio.h"
#include "attrib/gatt.h"
+#include "hog-lib.h"
#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
-#define HOG_INFO_UUID 0x2A4A
-#define HOG_REPORT_MAP_UUID 0x2A4B
-#define HOG_REPORT_UUID 0x2A4D
-#define HOG_PROTO_MODE_UUID 0x2A4E
-#define HOG_CONTROL_POINT_UUID 0x2A4C
-
-#define HOG_REPORT_TYPE_INPUT 1
-#define HOG_REPORT_TYPE_OUTPUT 2
-#define HOG_REPORT_TYPE_FEATURE 3
-
-#define HOG_PROTO_MODE_BOOT 0
-#define HOG_PROTO_MODE_REPORT 1
-
-#define HOG_REPORT_MAP_MAX_SIZE 512
-#define HID_INFO_SIZE 4
-#define ATT_NOTIFICATION_HEADER_SIZE 3
-
struct hog_device {
- uint16_t id;
- struct btd_device *device;
- GAttrib *attrib;
guint attioid;
- struct gatt_primary *hog_primary;
- GSList *reports;
- struct bt_uhid *uhid;
- gboolean has_report_id;
- uint16_t bcdhid;
- uint8_t bcountrycode;
- uint16_t proto_mode_handle;
- uint16_t ctrlpt_handle;
- uint8_t flags;
- guint getrep_att;
- uint16_t getrep_id;
- guint setrep_att;
- uint16_t setrep_id;
-};
-
-struct report {
- uint8_t id;
- uint8_t type;
- guint notifyid;
- struct gatt_char *decl;
- struct hog_device *hogdev;
+ struct btd_device *device;
+ struct bt_hog *hog;
};
static gboolean suspend_supported = FALSE;
-static GSList *devices = NULL;
-
-static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
-{
- struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
- struct uhid_event ev;
- uint8_t *buf;
- int err;
-
- if (len < ATT_NOTIFICATION_HEADER_SIZE) {
- error("Malformed ATT notification");
- return;
- }
-
- pdu += ATT_NOTIFICATION_HEADER_SIZE;
- len -= ATT_NOTIFICATION_HEADER_SIZE;
-
- memset(&ev, 0, sizeof(ev));
- ev.type = UHID_INPUT;
- buf = ev.u.input.data;
-
- if (hogdev->has_report_id) {
- buf[0] = report->id;
- len = MIN(len, sizeof(ev.u.input.data) - 1);
- memcpy(buf + 1, pdu, len);
- ev.u.input.size = ++len;
- } else {
- len = MIN(len, sizeof(ev.u.input.data));
- memcpy(buf, pdu, len);
- ev.u.input.size = len;
- }
-
- err = bt_uhid_send(hogdev->uhid, &ev);
- if (err < 0) {
- error("bt_uhid_send: %s (%d)", strerror(-err), -err);
- return;
- }
-
- DBG("HoG report (%u bytes)", ev.u.input.size);
-}
-
-static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
-
- if (status != 0) {
- error("Write report characteristic descriptor failed: %s",
- att_ecode2str(status));
- return;
- }
-
- report->notifyid = g_attrib_register(hogdev->attrib,
- ATT_OP_HANDLE_NOTIFY,
- report->decl->value_handle,
- report_value_cb, report, NULL);
-
- DBG("Report characteristic descriptor written: notifications enabled");
-}
-
-static void write_ccc(uint16_t handle, gpointer user_data)
-{
- struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
- uint8_t value[] = { 0x01, 0x00 };
-
- gatt_write_char(hogdev->attrib, handle, value, sizeof(value),
- report_ccc_written_cb, report);
-}
-
-static void report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct report *report = user_data;
-
- if (status != 0) {
- error("Read Report Reference descriptor failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (plen != 3) {
- error("Malformed ATT read response");
- return;
- }
-
- report->id = pdu[1];
- report->type = pdu[2];
- DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
-}
-
-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data);
-
-
-static void discover_descriptor_cb(uint8_t status, GSList *descs,
- void *user_data)
-{
- struct report *report;
- struct hog_device *hogdev;
- GAttrib *attrib = NULL;
-
- if (status != 0) {
- error("Discover all descriptors failed: %s",
- att_ecode2str(status));
- return;
- }
-
- for ( ; descs; descs = descs->next) {
- struct gatt_desc *desc = descs->data;
-
- switch (desc->uuid16) {
- case GATT_CLIENT_CHARAC_CFG_UUID:
- report = user_data;
- write_ccc(desc->handle, report);
- break;
- case GATT_REPORT_REFERENCE:
- report = user_data;
- attrib = report->hogdev->attrib;
- gatt_read_char(attrib, desc->handle,
- report_reference_cb, report);
- break;
- case GATT_EXTERNAL_REPORT_REFERENCE:
- hogdev = user_data;
- attrib = hogdev->attrib;
- gatt_read_char(attrib, desc->handle,
- external_report_reference_cb, hogdev);
- break;
- }
- }
-}
-
-static void discover_descriptor(GAttrib *attrib, uint16_t start, uint16_t end,
- gpointer user_data)
-{
- if (start > end)
- return;
-
- gatt_discover_desc(attrib, start, end, NULL,
- discover_descriptor_cb, user_data);
-}
-
-static void external_service_char_cb(uint8_t status, GSList *chars,
- void *user_data)
-{
- struct hog_device *hogdev = user_data;
- struct gatt_primary *prim = hogdev->hog_primary;
- struct report *report;
- GSList *l;
-
- if (status != 0) {
- const char *str = att_ecode2str(status);
- DBG("Discover external service characteristic failed: %s", str);
- return;
- }
-
- for (l = chars; l; l = g_slist_next(l)) {
- struct gatt_char *chr, *next;
- uint16_t start, end;
-
- chr = l->data;
- next = l->next ? l->next->data : NULL;
-
- DBG("0x%04x UUID: %s properties: %02x",
- chr->handle, chr->uuid, chr->properties);
-
- report = g_new0(struct report, 1);
- report->hogdev = hogdev;
- report->decl = g_memdup(chr, sizeof(*chr));
- hogdev->reports = g_slist_append(hogdev->reports, report);
- start = chr->value_handle + 1;
- end = (next ? next->handle - 1 : prim->range.end);
- discover_descriptor(hogdev->attrib, start, end, report);
- }
-}
-
-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- uint16_t uuid16;
- bt_uuid_t uuid;
-
- if (status != 0) {
- error("Read External Report Reference descriptor failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (plen != 3) {
- error("Malformed ATT read response");
- return;
- }
-
- uuid16 = get_le16(&pdu[1]);
- DBG("External report reference read, external report characteristic "
- "UUID: 0x%04x", uuid16);
- bt_uuid16_create(&uuid, uuid16);
- gatt_discover_char(hogdev->attrib, 0x00, 0xff, &uuid,
- external_service_char_cb, hogdev);
-}
-
-static int report_cmp(gconstpointer a, gconstpointer b)
-{
- const struct report *ra = a, *rb = b;
-
- /* sort by type first.. */
- if (ra->type != rb->type)
- return ra->type - rb->type;
-
- /* ..then by id */
- return ra->id - rb->id;
-}
-
-static void output_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- if (status != 0) {
- error("Write output report failed: %s", att_ecode2str(status));
- return;
- }
-}
-
-static struct report *find_report(struct hog_device *hogdev, uint8_t type, uint8_t id)
-{
- struct report cmp;
- GSList *l;
-
- switch (type) {
- case UHID_FEATURE_REPORT:
- cmp.type = HOG_REPORT_TYPE_FEATURE;
- break;
- case UHID_OUTPUT_REPORT:
- cmp.type = HOG_REPORT_TYPE_OUTPUT;
- break;
- case UHID_INPUT_REPORT:
- cmp.type = HOG_REPORT_TYPE_INPUT;
- break;
- default:
- return NULL;
- }
-
- cmp.id = hogdev->has_report_id ? id : 0;
-
- l = g_slist_find_custom(hogdev->reports, &cmp, report_cmp);
-
- return l ? l->data : NULL;
-}
-
-static void forward_report(struct uhid_event *ev, void *user_data)
-{
- struct hog_device *hogdev = user_data;
- struct report *report;
- void *data;
- int size;
-
- report = find_report(hogdev, ev->u.output.rtype, ev->u.output.data[0]);
- if (!report)
- return;
-
- data = ev->u.output.data;
- size = ev->u.output.size;
- if (hogdev->has_report_id && size > 0) {
- data++;
- --size;
- }
-
- DBG("Sending report type %d ID %d to handle 0x%X", report->type,
- report->id, report->decl->value_handle);
-
- if (hogdev->attrib == NULL)
- return;
-
- if (report->decl->properties & GATT_CHR_PROP_WRITE)
- gatt_write_char(hogdev->attrib, report->decl->value_handle,
- data, size, output_written_cb, hogdev);
- else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
- gatt_write_cmd(hogdev->attrib, report->decl->value_handle,
- data, size, NULL, NULL);
-}
-
-static void set_report_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- struct uhid_event rsp;
- int err;
-
- hogdev->setrep_att = 0;
-
- memset(&rsp, 0, sizeof(rsp));
- rsp.type = UHID_SET_REPORT_REPLY;
- rsp.u.set_report_reply.id = hogdev->setrep_id;
- rsp.u.set_report_reply.err = status;
-
- if (status != 0)
- error("Error setting Report value: %s", att_ecode2str(status));
-
- err = bt_uhid_send(hogdev->uhid, &rsp);
- if (err < 0)
- error("bt_uhid_send: %s", strerror(-err));
-}
-
-static void set_report(struct uhid_event *ev, void *user_data)
-{
- struct hog_device *hogdev = user_data;
- struct report *report;
- void *data;
- int size;
- int err;
-
- /* uhid never sends reqs in parallel; if there's a req, it timed out */
- if (hogdev->setrep_att) {
- g_attrib_cancel(hogdev->attrib, hogdev->setrep_att);
- hogdev->setrep_att = 0;
- }
-
- hogdev->setrep_id = ev->u.set_report.id;
-
- report = find_report(hogdev, ev->u.set_report.rtype,
- ev->u.set_report.rnum);
- if (!report) {
- err = ENOTSUP;
- goto fail;
- }
-
- data = ev->u.set_report.data;
- size = ev->u.set_report.size;
- if (hogdev->has_report_id && size > 0) {
- data++;
- --size;
- }
-
- DBG("Sending report type %d ID %d to handle 0x%X", report->type,
- report->id, report->decl->value_handle);
-
- if (hogdev->attrib == NULL)
- return;
-
- hogdev->setrep_att = gatt_write_char(hogdev->attrib,
- report->decl->value_handle,
- data, size, set_report_cb,
- hogdev);
- if (!hogdev->setrep_att) {
- err = ENOMEM;
- goto fail;
- }
-
- return;
-fail:
- /* cancel the request on failure */
- set_report_cb(err, NULL, 0, hogdev);
-}
-
-static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- struct uhid_event rsp;
- int err;
-
- hogdev->getrep_att = 0;
-
- memset(&rsp, 0, sizeof(rsp));
- rsp.type = UHID_GET_REPORT_REPLY;
- rsp.u.get_report_reply.id = hogdev->getrep_id;
-
- if (status != 0) {
- error("Error reading Report value: %s", att_ecode2str(status));
- goto exit;
- }
-
- if (len == 0) {
- error("Error reading Report, length %d", len);
- status = EIO;
- goto exit;
- }
-
- if (pdu[0] != 0x0b) {
- error("Error reading Report, invalid response: %02x", pdu[0]);
- status = EPROTO;
- goto exit;
- }
-
- --len;
- ++pdu;
- if (hogdev->has_report_id && len > 0) {
- --len;
- ++pdu;
- }
-
- rsp.u.get_report_reply.size = len;
- memcpy(rsp.u.get_report_reply.data, pdu, len);
-
-exit:
- rsp.u.get_report_reply.err = status;
- err = bt_uhid_send(hogdev->uhid, &rsp);
- if (err < 0)
- error("bt_uhid_send: %s", strerror(-err));
-}
-
-static void get_report(struct uhid_event *ev, void *user_data)
-{
- struct hog_device *hogdev = user_data;
- struct report *report;
- guint8 err;
-
- /* uhid never sends reqs in parallel; if there's a req, it timed out */
- if (hogdev->getrep_att) {
- g_attrib_cancel(hogdev->attrib, hogdev->getrep_att);
- hogdev->getrep_att = 0;
- }
-
- hogdev->getrep_id = ev->u.get_report.id;
-
- report = find_report(hogdev, ev->u.get_report.rtype,
- ev->u.get_report.rnum);
- if (!report) {
- err = ENOTSUP;
- goto fail;
- }
-
- hogdev->getrep_att = gatt_read_char(hogdev->attrib,
- report->decl->value_handle,
- get_report_cb, hogdev);
- if (!hogdev->getrep_att) {
- err = ENOMEM;
- goto fail;
- }
-
- return;
-
-fail:
- /* cancel the request on failure */
- get_report_cb(err, NULL, 0, hogdev);
-}
-
-static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
- bool *is_long)
-{
- if (!blen)
- return false;
-
- *is_long = (buf[0] == 0xfe);
-
- if (*is_long) {
- if (blen < 3)
- return false;
-
- /*
- * long item:
- * byte 0 -> 0xFE
- * byte 1 -> data size
- * byte 2 -> tag
- * + data
- */
-
- *len = buf[1] + 3;
- } else {
- uint8_t b_size;
-
- /*
- * short item:
- * byte 0[1..0] -> data size (=0, 1, 2, 4)
- * byte 0[3..2] -> type
- * byte 0[7..4] -> tag
- * + data
- */
-
- b_size = buf[0] & 0x03;
- *len = (b_size ? 1 << (b_size - 1) : 0) + 1;
- }
-
- /* item length should be no more than input buffer length */
- return *len <= blen;
-}
-
-static char *item2string(char *str, uint8_t *buf, uint8_t len)
-{
- char *p = str;
- int i;
-
- /*
- * Since long item tags are not defined except for vendor ones, we
- * just ensure that short items are printed properly (up to 5 bytes).
- */
- for (i = 0; i < 6 && i < len; i++)
- p += sprintf(p, " %02x", buf[i]);
-
- /*
- * If there are some data left, just add continuation mark to indicate
- * this.
- */
- if (i < len)
- sprintf(p, " ...");
-
- return str;
-}
-
-static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- struct btd_adapter *adapter = device_get_adapter(hogdev->device);
- uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
- struct uhid_event ev;
- uint16_t vendor_src, vendor, product, version;
- ssize_t vlen;
- char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
- int i, err;
-
- if (status != 0) {
- error("Report Map read failed: %s", att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, plen, value, sizeof(value));
- if (vlen < 0) {
- error("ATT protocol error");
- return;
- }
-
- DBG("Report MAP:");
- for (i = 0; i < vlen;) {
- ssize_t ilen = 0;
- bool long_item = false;
-
- if (get_descriptor_item_info(&value[i], vlen - i, &ilen,
- &long_item)) {
- /* Report ID is short item with prefix 100001xx */
- if (!long_item && (value[i] & 0xfc) == 0x84)
- hogdev->has_report_id = TRUE;
-
- DBG("\t%s", item2string(itemstr, &value[i], ilen));
-
- i += ilen;
- } else {
- error("Report Map parsing failed at %d", i);
-
- /* Just print remaining items at once and break */
- DBG("\t%s", item2string(itemstr, &value[i], vlen - i));
- break;
- }
- }
-
- vendor_src = btd_device_get_vendor_src(hogdev->device);
- vendor = btd_device_get_vendor(hogdev->device);
- product = btd_device_get_product(hogdev->device);
- version = btd_device_get_version(hogdev->device);
- DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
- "version=0x%X", vendor_src, vendor, product, version);
-
- /* create uHID device */
- memset(&ev, 0, sizeof(ev));
- ev.type = UHID_CREATE;
- if (device_name_known(hogdev->device))
- device_get_name(hogdev->device, (char *) ev.u.create.name,
- sizeof(ev.u.create.name));
- else
- strcpy((char *) ev.u.create.name, "bluez-hog-device");
- ba2str(btd_adapter_get_address(adapter), (char *) ev.u.create.phys);
- ba2str(device_get_address(hogdev->device), (char *) ev.u.create.uniq);
- ev.u.create.vendor = vendor;
- ev.u.create.product = product;
- ev.u.create.version = version;
- ev.u.create.country = hogdev->bcountrycode;
- ev.u.create.bus = BUS_BLUETOOTH;
- ev.u.create.rd_data = value;
- ev.u.create.rd_size = vlen;
-
- err = bt_uhid_send(hogdev->uhid, &ev);
- if (err < 0) {
- error("bt_uhid_send: %s", strerror(-err));
- return;
- }
-
- bt_uhid_register(hogdev->uhid, UHID_OUTPUT, forward_report, hogdev);
- bt_uhid_register(hogdev->uhid, UHID_SET_REPORT, set_report, hogdev);
- bt_uhid_register(hogdev->uhid, UHID_GET_REPORT, get_report, hogdev);
-}
-
-static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- uint8_t value[HID_INFO_SIZE];
- ssize_t vlen;
-
- if (status != 0) {
- error("HID Information read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, plen, value, sizeof(value));
- if (vlen != 4) {
- error("ATT protocol error");
- return;
- }
-
- hogdev->bcdhid = get_le16(&value[0]);
- hogdev->bcountrycode = value[2];
- hogdev->flags = value[3];
-
- DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X",
- hogdev->bcdhid, hogdev->bcountrycode, hogdev->flags);
-}
-
-static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- uint8_t value;
- ssize_t vlen;
-
- if (status != 0) {
- error("Protocol Mode characteristic read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, plen, &value, sizeof(value));
- if (vlen < 0) {
- error("ATT protocol error");
- return;
- }
-
- if (value == HOG_PROTO_MODE_BOOT) {
- uint8_t nval = HOG_PROTO_MODE_REPORT;
-
- DBG("HoG device 0x%04X is operating in Boot Procotol Mode",
- hogdev->id);
-
- gatt_write_cmd(hogdev->attrib, hogdev->proto_mode_handle, &nval,
- sizeof(nval), NULL, NULL);
- } else if (value == HOG_PROTO_MODE_REPORT)
- DBG("HoG device 0x%04X is operating in Report Protocol Mode",
- hogdev->id);
-}
-
-static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
-{
- struct hog_device *hogdev = user_data;
- struct gatt_primary *prim = hogdev->hog_primary;
- bt_uuid_t report_uuid, report_map_uuid, info_uuid;
- bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
- struct report *report;
- GSList *l;
- uint16_t info_handle = 0, proto_mode_handle = 0;
-
- if (status != 0) {
- const char *str = att_ecode2str(status);
- DBG("Discover all characteristics failed: %s", str);
- return;
- }
-
- bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
- bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
- bt_uuid16_create(&info_uuid, HOG_INFO_UUID);
- bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
- bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
-
- for (l = chars; l; l = g_slist_next(l)) {
- struct gatt_char *chr, *next;
- bt_uuid_t uuid;
- uint16_t start, end;
-
- chr = l->data;
- next = l->next ? l->next->data : NULL;
-
- DBG("0x%04x UUID: %s properties: %02x",
- chr->handle, chr->uuid, chr->properties);
-
- bt_string_to_uuid(&uuid, chr->uuid);
-
- start = chr->value_handle + 1;
- end = (next ? next->handle - 1 : prim->range.end);
-
- if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
- report = g_new0(struct report, 1);
- report->hogdev = hogdev;
- report->decl = g_memdup(chr, sizeof(*chr));
- hogdev->reports = g_slist_append(hogdev->reports,
- report);
- discover_descriptor(hogdev->attrib, start, end, report);
- } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
- gatt_read_char(hogdev->attrib, chr->value_handle,
- report_map_read_cb, hogdev);
- discover_descriptor(hogdev->attrib, start, end, hogdev);
- } else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
- info_handle = chr->value_handle;
- else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
- proto_mode_handle = chr->value_handle;
- else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
- hogdev->ctrlpt_handle = chr->value_handle;
- }
-
- if (proto_mode_handle) {
- hogdev->proto_mode_handle = proto_mode_handle;
- gatt_read_char(hogdev->attrib, proto_mode_handle,
- proto_mode_read_cb, hogdev);
- }
-
- if (info_handle)
- gatt_read_char(hogdev->attrib, info_handle, info_read_cb,
- hogdev);
-}
+static struct queue *devices = NULL;
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
- struct hog_device *hogdev = user_data;
- struct gatt_primary *prim = hogdev->hog_primary;
- GSList *l;
+ struct hog_device *dev = user_data;
DBG("HoG connected");
- hogdev->attrib = g_attrib_ref(attrib);
-
- if (hogdev->reports == NULL) {
- gatt_discover_char(hogdev->attrib, prim->range.start,
- prim->range.end, NULL,
- char_discovered_cb, hogdev);
- return;
- }
-
- for (l = hogdev->reports; l; l = l->next) {
- struct report *r = l->data;
-
- r->notifyid = g_attrib_register(hogdev->attrib,
- ATT_OP_HANDLE_NOTIFY,
- r->decl->value_handle,
- report_value_cb, r, NULL);
- }
+ bt_hog_attach(dev->hog, attrib);
}
static void attio_disconnected_cb(gpointer user_data)
{
- struct hog_device *hogdev = user_data;
- GSList *l;
+ struct hog_device *dev = user_data;
DBG("HoG disconnected");
- for (l = hogdev->reports; l; l = l->next) {
- struct report *r = l->data;
-
- g_attrib_unregister(hogdev->attrib, r->notifyid);
- }
-
- g_attrib_unref(hogdev->attrib);
- hogdev->attrib = NULL;
+ bt_hog_detach(dev->hog);
}
-static struct hog_device *hog_new_device(struct btd_device *device,
- uint16_t id)
-{
- struct hog_device *hogdev;
-
- hogdev = g_try_new0(struct hog_device, 1);
- if (!hogdev)
- return NULL;
-
- hogdev->id = id;
- hogdev->device = btd_device_ref(device);
-
- return hogdev;
-}
-
-static void report_free(void *data)
-{
- struct report *report = data;
- struct hog_device *hogdev = report->hogdev;
-
- if (hogdev->attrib)
- g_attrib_unregister(hogdev->attrib, report->notifyid);
-
- g_free(report->decl);
- g_free(report);
-}
-
-static void hog_free_device(struct hog_device *hogdev)
-{
- btd_device_unref(hogdev->device);
- g_slist_free_full(hogdev->reports, report_free);
- g_attrib_unref(hogdev->attrib);
- g_free(hogdev->hog_primary);
- g_free(hogdev);
-}
-
-static struct hog_device *hog_register_device(struct btd_device *device,
+static struct hog_device *hog_device_new(struct btd_device *device,
struct gatt_primary *prim)
{
- struct hog_device *hogdev;
+ struct hog_device *dev;
+ char name[248];
+ uint16_t vendor, product, version;
- hogdev = hog_new_device(device, prim->range.start);
- if (!hogdev)
- return NULL;
+ if (device_name_known(device))
+ device_get_name(device, name, sizeof(name));
+ else
+ strcpy(name, "bluez-hog-device");
- hogdev->uhid = bt_uhid_new_default();
- if (!hogdev->uhid) {
- error("bt_uhid_new_default: failed");
- hog_free_device(hogdev);
- return NULL;
- }
+ vendor = btd_device_get_vendor(device);
+ product = btd_device_get_product(device);
+ version = btd_device_get_version(device);
- hogdev->hog_primary = g_memdup(prim, sizeof(*prim));
+ DBG("name=%s vendor=0x%X, product=0x%X, version=0x%X", name, vendor,
+ product, version);
- hogdev->attioid = btd_device_add_attio_callback(device,
+ dev = new0(struct hog_device, 1);
+ dev->device = btd_device_ref(device);
+ dev->hog = bt_hog_new_default(name, vendor, product, version, prim);
+
+ /*
+ * TODO: Remove attio callback and use .accept once using
+ * bt_gatt_client.
+ */
+ dev->attioid = btd_device_add_attio_callback(device,
attio_connected_cb,
attio_disconnected_cb,
- hogdev);
+ dev);
- return hogdev;
-}
+ if (!devices)
+ devices = queue_new();
-static int hog_unregister_device(struct hog_device *hogdev)
-{
- btd_device_remove_attio_callback(hogdev->device, hogdev->attioid);
- bt_uhid_unref(hogdev->uhid);
- hog_free_device(hogdev);
+ queue_push_tail(devices, dev);
- return 0;
+ return dev;
}
-static int set_control_point(struct hog_device *hogdev, gboolean suspend)
+static void hog_device_free(void *data)
{
- uint8_t value = suspend ? 0x00 : 0x01;
-
- if (hogdev->attrib == NULL)
- return -ENOTCONN;
-
- DBG("0x%4X HID Control Point: %s", hogdev->id, suspend ?
- "Suspend" : "Exit Suspend");
-
- if (hogdev->ctrlpt_handle == 0)
- return -ENOTSUP;
+ struct hog_device *dev = data;
- gatt_write_cmd(hogdev->attrib, hogdev->ctrlpt_handle, &value,
- sizeof(value), NULL, NULL);
+ queue_remove(devices, dev);
+ if (queue_isempty(devices)) {
+ queue_destroy(devices, NULL);
+ devices = NULL;
+ }
- return 0;
+ btd_device_remove_attio_callback(dev->device, dev->attioid);
+ btd_device_unref(dev->device);
+ bt_hog_unref(dev->hog);
+ free(dev);
}
static void set_suspend(gpointer data, gpointer user_data)
{
- struct hog_device *hogdev = data;
+ struct hog_device *dev = data;
gboolean suspend = GPOINTER_TO_INT(user_data);
- set_control_point(hogdev, suspend);
+ bt_hog_set_control_point(dev->hog, suspend);
}
static void suspend_callback(void)
@@ -962,7 +157,7 @@ static void suspend_callback(void)
DBG("Suspending ...");
- g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+ queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
}
static void resume_callback(void)
@@ -971,7 +166,7 @@ static void resume_callback(void)
DBG("Resuming ...");
- g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+ queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
}
static int hog_probe(struct btd_service *service)
@@ -988,41 +183,28 @@ static int hog_probe(struct btd_service *service)
for (l = primaries; l; l = g_slist_next(l)) {
struct gatt_primary *prim = l->data;
- struct hog_device *hogdev;
+ struct hog_device *dev;
if (strcmp(prim->uuid, HOG_UUID) != 0)
continue;
- hogdev = hog_register_device(device, prim);
- if (hogdev == NULL)
- continue;
-
- devices = g_slist_append(devices, hogdev);
+ dev = hog_device_new(device, prim);
+ btd_service_set_user_data(service, dev);
+ return 0;
}
- return 0;
-}
-
-static void remove_device(gpointer a, gpointer b)
-{
- struct hog_device *hogdev = a;
- struct btd_device *device = b;
-
- if (hogdev->device != device)
- return;
-
- devices = g_slist_remove(devices, hogdev);
- hog_unregister_device(hogdev);
+ return -EINVAL;
}
static void hog_remove(struct btd_service *service)
{
+ struct hog_device *dev = btd_service_get_user_data(service);
struct btd_device *device = btd_service_get_device(service);
const char *path = device_get_path(device);
DBG("path %s", path);
- g_slist_foreach(devices, remove_device, device);
+ hog_device_free(dev);
}
static struct btd_profile hog_profile = {
diff --git a/profiles/input/suspend-none.c b/profiles/input/suspend-none.c
new file mode 100644
index 00000000..c619bb11
--- /dev/null
+++ b/profiles/input/suspend-none.c
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Nordic Semiconductor Inc.
+ * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "src/log.h"
+#include "suspend.h"
+
+int suspend_init(suspend_event suspend, resume_event resume)
+{
+ DBG("");
+
+ return 0;
+}
+
+void suspend_exit(void)
+{
+ DBG("");
+}
diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index a4cc00b6..95a8e74f 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -160,9 +160,7 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
req.sock = sk;
req.role = role;
-#ifdef __TIZEN_PATCH__
req.flags = (1 << BNEP_SETUP_RESPONSE);
-#endif
if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
int err = -errno;
error("bnep: Failed to add device %s: %s(%d)",
@@ -174,7 +172,6 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
return 0;
}
-#ifdef __TIZEN_PATCH__
static uint32_t bnep_getsuppfeat(void)
{
uint32_t feat;
@@ -186,7 +183,6 @@ static uint32_t bnep_getsuppfeat(void)
return feat;
}
-#endif
static int bnep_if_up(const char *devname)
{
@@ -599,13 +595,9 @@ static uint16_t bnep_setup_decode(int sk, struct bnep_setup_conn_req *req,
uint8_t *dest, *source;
uint32_t val;
-#ifdef __TIZEN_PATCH__
if (((req->type != BNEP_CONTROL) &&
(req->type != (BNEP_CONTROL | BNEP_EXT_HEADER))) ||
req->ctrl != BNEP_SETUP_CONN_REQ)
-#else
- if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
-#endif
return BNEP_CONN_NOT_ALLOWED;
dest = req->service;
@@ -676,7 +668,6 @@ int bnep_conndel_wrapper(const bdaddr_t *dst)
}
#endif
-#ifdef __TIZEN_PATCH__
static int bnep_server_add_legacy(int sk, uint16_t dst, char *bridge,
char *iface, const bdaddr_t *addr,
uint8_t *setup_data, int len)
@@ -697,6 +688,15 @@ static int bnep_server_add_legacy(int sk, uint16_t dst, char *bridge,
goto reply;
}
+#ifndef __TIZEN_PATCH__
+ err = bnep_add_to_bridge(iface, bridge);
+ if (err < 0) {
+ bnep_conndel(addr);
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+#endif
+
err = bnep_if_up(iface);
if (err < 0) {
bnep_del_from_bridge(iface, bridge);
@@ -710,21 +710,18 @@ static int bnep_server_add_legacy(int sk, uint16_t dst, char *bridge,
reply:
if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
err = -errno;
- error("bnep: send ctrl rsp error: %s (%d)", strerror(errno),
- errno);
+ error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
+ -err);
}
return err;
}
-#endif
int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
uint8_t *setup_data, int len)
{
int err;
-#ifdef __TIZEN_PATCH__
uint32_t feat;
-#endif
uint16_t rsp, dst;
struct bnep_setup_conn_req *req = (void *) setup_data;
@@ -748,14 +745,9 @@ int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
err = -rsp;
error("bnep: error while decoding setup connection request: %d",
rsp);
-#ifdef __TIZEN_PATCH__
goto failed;
-#else
- goto reply;
-#endif
}
-#ifdef __TIZEN_PATCH__
feat = bnep_getsuppfeat();
/*
@@ -766,40 +758,29 @@ int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
if (!feat || !(feat & (1 << BNEP_SETUP_RESPONSE)))
return bnep_server_add_legacy(sk, dst, bridge, iface, addr,
setup_data, len);
-#endif
err = bnep_connadd(sk, dst, iface);
if (err < 0) {
rsp = BNEP_CONN_NOT_ALLOWED;
-#ifdef __TIZEN_PATCH__
goto failed;
-#else
- goto reply;
-#endif
}
#ifndef __TIZEN_PATCH__
err = bnep_add_to_bridge(iface, bridge);
- if (err < 0) {
- bnep_conndel(addr);
- return err;
- }
+ if (err < 0)
+ goto failed_conn;
#endif
err = bnep_if_up(iface);
if (err < 0)
-#ifdef __TIZEN_PATCH__
goto failed_bridge;
-#else
- rsp = BNEP_CONN_NOT_ALLOWED;
-#endif
-#ifdef __TIZEN_PATCH__
return 0;
failed_bridge:
bnep_del_from_bridge(iface, bridge);
+failed_conn:
bnep_conndel(addr);
return err;
@@ -810,14 +791,6 @@ failed:
error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
-err);
}
-#else
-reply:
- if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
- err = -errno;
- error("bnep: send ctrl rsp error: %s (%d)", strerror(errno),
- errno);
- }
-#endif
return err;
}
diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index e19e945e..c86f679f 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
@@ -309,11 +309,8 @@ static DBusMessage *local_connect(DBusConnection *conn,
id = get_pan_srv_id(svc);
bt_uuid16_create(&uuid16, id);
-#ifdef __TIZEN_PATCH__
bt_uuid_to_uuid128(&uuid16, &uuid128);
-#else
- bt_uuid_to_uuid128(&uuid128, &uuid16);
-#endif
+
if (bt_uuid_to_string(&uuid128, uuid_str, MAX_LEN_UUID_STR) < 0)
return btd_error_invalid_args(msg);
@@ -459,9 +456,7 @@ static gboolean network_property_get_uuid(const GDBusPropertyTable *property,
struct network_peer *peer = data;
struct network_conn *nc;
char uuid_str[MAX_LEN_UUID_STR];
-#ifdef __TIZEN_PATCH__
const char *uuid = uuid_str;
-#endif
bt_uuid_t uuid16, uuid128;
nc = find_connection_by_state(peer->connections, CONNECTED);
@@ -469,18 +464,10 @@ static gboolean network_property_get_uuid(const GDBusPropertyTable *property,
return FALSE;
bt_uuid16_create(&uuid16, nc->id);
-#ifdef __TIZEN_PATCH__
bt_uuid_to_uuid128(&uuid16, &uuid128);
-#else
- bt_uuid_to_uuid128(&uuid128, &uuid16);
-#endif
bt_uuid_to_string(&uuid128, uuid_str, MAX_LEN_UUID_STR);
-#ifdef __TIZEN_PATCH__
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
-#else
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid_str);
-#endif
return TRUE;
}
diff --git a/profiles/network/server.c b/profiles/network/server.c
index 2450fbea..214bc214 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
@@ -419,16 +419,11 @@ static gboolean bnep_setup(GIOChannel *chan,
sk = g_io_channel_unix_get_fd(chan);
-#ifdef __TIZEN_PATCH__
/*
* BNEP_SETUP_CONNECTION_REQUEST_MSG should be read and left in case
* of kernel setup connection msg handling.
*/
n = recv(sk, packet, sizeof(packet), MSG_PEEK);
-#else
- /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
- n = read(sk, packet, sizeof(packet));
-#endif
if (n < 0) {
error("read(): %s(%d)", strerror(errno), errno);
return FALSE;
diff --git a/profiles/scanparam/scan.c b/profiles/scanparam/scan.c
index fbda8a8b..4015b3f8 100644
--- a/profiles/scanparam/scan.c
+++ b/profiles/scanparam/scan.c
@@ -40,10 +40,11 @@
#include "src/profile.h"
#include "src/service.h"
#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
#include "attrib/att.h"
-#include "attrib/gattrib.h"
-#include "attrib/gatt.h"
-#include "src/attio.h"
#define SCAN_INTERVAL_WIN_UUID 0x2A4F
#define SCAN_REFRESH_UUID 0x2A31
@@ -54,203 +55,209 @@
struct scan {
struct btd_device *device;
- GAttrib *attrib;
- struct att_range range;
- guint attioid;
- uint16_t interval;
- uint16_t window;
+ struct gatt_db *db;
+ struct bt_gatt_client *client;
+ struct gatt_db_attribute *attr;
uint16_t iwhandle;
- uint16_t refresh_handle;
guint refresh_cb_id;
};
-static void write_scan_params(GAttrib *attrib, uint16_t handle)
+static GSList *devices;
+
+static void scan_free(struct scan *scan)
+{
+ bt_gatt_client_unregister_notify(scan->client, scan->refresh_cb_id);
+ gatt_db_unref(scan->db);
+ bt_gatt_client_unref(scan->client);
+ btd_device_unref(scan->device);
+ g_free(scan);
+}
+
+static int cmp_device(gconstpointer a, gconstpointer b)
+{
+ const struct scan *scan = a;
+ const struct btd_device *device = b;
+
+ return scan->device == device ? 0 : -1;
+}
+
+static void write_scan_params(struct scan *scan)
{
uint8_t value[4];
put_le16(SCAN_INTERVAL, &value[0]);
put_le16(SCAN_WINDOW, &value[2]);
- gatt_write_cmd(attrib, handle, value, sizeof(value), NULL, NULL);
+ bt_gatt_client_write_without_response(scan->client, scan->iwhandle,
+ false, value, sizeof(value));
}
-static void refresh_value_cb(const uint8_t *pdu, uint16_t len,
- gpointer user_data)
+static void refresh_value_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data)
{
struct scan *scan = user_data;
- DBG("Server requires refresh: %d", pdu[3]);
+ DBG("Server requires refresh: %d", value[3]);
- if (pdu[3] == SERVER_REQUIRES_REFRESH)
- write_scan_params(scan->attrib, scan->iwhandle);
+ if (value[3] == SERVER_REQUIRES_REFRESH)
+ write_scan_params(scan);
}
-static void ccc_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void refresh_ccc_written_cb(uint16_t att_ecode, void *user_data)
{
- struct scan *scan = user_data;
-
- if (status != 0) {
- error("Write Scan Refresh CCC failed: %s",
- att_ecode2str(status));
+ if (att_ecode != 0) {
+ error("Scan Refresh: notifications not enabled %s",
+ att_ecode2str(att_ecode));
return;
}
DBG("Scan Refresh: notification enabled");
-
- scan->refresh_cb_id = g_attrib_register(scan->attrib,
- ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
- refresh_value_cb, scan, NULL);
}
-static void discover_descriptor_cb(uint8_t status, GSList *descs,
- void *user_data)
+static void handle_refresh(struct scan *scan, uint16_t value_handle)
{
- struct scan *scan = user_data;
- struct gatt_desc *desc;
- uint8_t value[2];
+ DBG("Scan Refresh handle: 0x%04x", value_handle);
- if (status != 0) {
- error("Discover descriptors failed: %s", att_ecode2str(status));
- return;
- }
+ scan->refresh_cb_id = bt_gatt_client_register_notify(scan->client,
+ value_handle, refresh_ccc_written_cb,
+ refresh_value_cb, scan, NULL);
+}
+
+static void handle_iwin(struct scan *scan, uint16_t value_handle)
+{
+ scan->iwhandle = value_handle;
- /* There will be only one descriptor on list and it will be CCC */
- desc = descs->data;
+ DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
- put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
- gatt_write_char(scan->attrib, desc->handle, value, sizeof(value),
- ccc_written_cb, user_data);
+ write_scan_params(scan);
}
-static void refresh_discovered_cb(uint8_t status, GSList *chars,
+static void handle_characteristic(struct gatt_db_attribute *attr,
void *user_data)
{
struct scan *scan = user_data;
- struct gatt_char *chr;
- uint16_t start, end;
- bt_uuid_t uuid;
-
- if (status) {
- error("Scan Refresh %s", att_ecode2str(status));
- return;
- }
+ uint16_t value_handle;
+ bt_uuid_t uuid, scan_interval_wind_uuid, scan_refresh_uuid;
- if (!chars) {
- DBG("Scan Refresh not supported");
+ if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL,
+ &uuid)) {
+ error("Failed to obtain characteristic data");
return;
}
- chr = chars->data;
+ bt_uuid16_create(&scan_interval_wind_uuid, SCAN_INTERVAL_WIN_UUID);
+ bt_uuid16_create(&scan_refresh_uuid, SCAN_REFRESH_UUID);
- DBG("Scan Refresh handle: 0x%04x", chr->value_handle);
+ if (bt_uuid_cmp(&scan_interval_wind_uuid, &uuid) == 0)
+ handle_iwin(scan, value_handle);
+ else if (bt_uuid_cmp(&scan_refresh_uuid, &uuid) == 0)
+ handle_refresh(scan, value_handle);
+ else {
+ char uuid_str[MAX_LEN_UUID_STR];
- start = chr->value_handle + 1;
- end = scan->range.end;
-
- if (start > end)
- return;
-
- scan->refresh_handle = chr->value_handle;
-
- bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
-
- gatt_discover_desc(scan->attrib, start, end, &uuid,
- discover_descriptor_cb, user_data);
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+ DBG("Unsupported characteristic: %s", uuid_str);
+ }
}
-static void iwin_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+static void foreach_scan_param_service(struct gatt_db_attribute *attr,
+ void *user_data)
{
struct scan *scan = user_data;
- struct gatt_char *chr;
- if (status) {
- error("Discover Scan Interval Window: %s",
- att_ecode2str(status));
+ if (scan->attr) {
+ error("More than one scan params service exists for this "
+ "device");
return;
}
- chr = chars->data;
- scan->iwhandle = chr->value_handle;
-
- DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
-
- write_scan_params(scan->attrib, scan->iwhandle);
+ scan->attr = attr;
+ gatt_db_service_foreach_char(scan->attr, handle_characteristic, scan);
}
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+static int scan_param_accept(struct btd_service *service)
{
- struct scan *scan = user_data;
- bt_uuid_t iwin_uuid, refresh_uuid;
+ struct btd_device *device = btd_service_get_device(service);
+ struct gatt_db *db = btd_device_get_gatt_db(device);
+ struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+ bt_uuid_t scan_parameters_uuid;
+ struct scan *scan;
+ GSList *l;
+ char addr[18];
- scan->attrib = g_attrib_ref(attrib);
+ ba2str(device_get_address(device), addr);
+ DBG("Scan Parameters Client Driver profile accept (%s)", addr);
- if (scan->iwhandle) {
- write_scan_params(scan->attrib, scan->iwhandle);
- return;
+ l = g_slist_find_custom(devices, device, cmp_device);
+ if (!l) {
+ error("Scan Parameters service not handled by profile");
+ return -1;
}
- bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
- bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);
+ scan = l->data;
- gatt_discover_char(scan->attrib, scan->range.start, scan->range.end,
- &iwin_uuid, iwin_discovered_cb, scan);
+ /* Clean-up any old client/db and acquire the new ones */
+ scan->attr = NULL;
+ gatt_db_unref(scan->db);
+ bt_gatt_client_unref(scan->client);
- gatt_discover_char(scan->attrib, scan->range.start, scan->range.end,
- &refresh_uuid, refresh_discovered_cb, scan);
-}
-static void attio_disconnected_cb(gpointer user_data)
-{
- struct scan *scan = user_data;
+ scan->db = gatt_db_ref(db);
+ scan->client = bt_gatt_client_ref(client);
- g_attrib_unref(scan->attrib);
- scan->attrib = NULL;
+ bt_string_to_uuid(&scan_parameters_uuid, SCAN_PARAMETERS_UUID);
+ gatt_db_foreach_service(db, &scan_parameters_uuid,
+ foreach_scan_param_service, scan);
+
+ return 0;
}
-static int scan_register(struct btd_service *service, struct gatt_primary *prim)
+static void scan_param_remove(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
struct scan *scan;
+ GSList *l;
+ char addr[18];
- scan = g_new0(struct scan, 1);
- scan->device = btd_device_ref(device);
- scan->range = prim->range;
- scan->attioid = btd_device_add_attio_callback(device,
- attio_connected_cb,
- attio_disconnected_cb,
- scan);
-
- btd_service_set_user_data(service, scan);
+ ba2str(device_get_address(device), addr);
+ DBG("GAP profile remove (%s)", addr);
- return 0;
-}
-
-static void scan_param_remove(struct btd_service *service)
-{
- struct scan *scan = btd_service_get_user_data(service);
+ l = g_slist_find_custom(devices, device, cmp_device);
+ if (!l) {
+ error("GAP service not handled by profile");
+ return;
+ }
- if (scan->attrib != NULL && scan->refresh_cb_id > 0)
- g_attrib_unregister(scan->attrib, scan->refresh_cb_id);
+ scan = l->data;
- btd_device_remove_attio_callback(scan->device, scan->attioid);
- btd_device_unref(scan->device);
- g_attrib_unref(scan->attrib);
- g_free(scan);
+ devices = g_slist_remove(devices, scan);
+ scan_free(scan);
}
static int scan_param_probe(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
- struct gatt_primary *prim;
+ struct scan *scan;
+ GSList *l;
+ char addr[18];
- DBG("Probing Scan Parameters");
+ ba2str(device_get_address(device), addr);
+ DBG("Scan Parameters Client Driver profile probe (%s)", addr);
- prim = btd_device_get_primary(device, SCAN_PARAMETERS_UUID);
- if (!prim)
- return -EINVAL;
+ /* Ignore, if we were probed for this device already */
+ l = g_slist_find_custom(devices, device, cmp_device);
+ if (l) {
+ error("Profile probed twice for the same device!");
+ return -1;
+ }
- return scan_register(service, prim);
+ scan = g_new0(struct scan, 1);
+ if (!scan)
+ return -1;
+
+ scan->device = btd_device_ref(device);
+ devices = g_slist_append(devices, scan);
+ return 0;
}
static struct btd_profile scan_profile = {
@@ -258,6 +265,7 @@ static struct btd_profile scan_profile = {
.remote_uuid = SCAN_PARAMETERS_UUID,
.device_probe = scan_param_probe,
.device_remove = scan_param_remove,
+ .accept = scan_param_accept,
};
static int scan_param_init(void)
diff --git a/profiles/scanparam/scpp.c b/profiles/scanparam/scpp.c
new file mode 100644
index 00000000..df65d2c1
--- /dev/null
+++ b/profiles/scanparam/scpp.c
@@ -0,0 +1,355 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Nordic Semiconductor Inc.
+ * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "src/log.h"
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
+
+#include "profiles/scanparam/scpp.h"
+
+#define SCAN_INTERVAL_WIN_UUID 0x2A4F
+#define SCAN_REFRESH_UUID 0x2A31
+
+#define SCAN_INTERVAL 0x0060
+#define SCAN_WINDOW 0x0030
+#define SERVER_REQUIRES_REFRESH 0x00
+
+struct bt_scpp {
+ int ref_count;
+ GAttrib *attrib;
+ struct gatt_primary *primary;
+ uint16_t interval;
+ uint16_t window;
+ uint16_t iwhandle;
+ uint16_t refresh_handle;
+ guint refresh_cb_id;
+ struct queue *gatt_op;
+};
+
+static void discover_char(struct bt_scpp *scpp, GAttrib *attrib,
+ uint16_t start, uint16_t end,
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
+{
+ unsigned int id;
+
+ id = gatt_discover_char(attrib, start, end, uuid, func, user_data);
+
+ queue_push_head(scpp->gatt_op, UINT_TO_PTR(id));
+}
+
+static void discover_desc(struct bt_scpp *scpp, GAttrib *attrib,
+ uint16_t start, uint16_t end, bt_uuid_t *uuid,
+ gatt_cb_t func, gpointer user_data)
+{
+ unsigned int id;
+
+ id = gatt_discover_desc(attrib, start, end, uuid, func, user_data);
+
+ queue_push_head(scpp->gatt_op, UINT_TO_PTR(id));
+}
+
+static void write_char(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
+ const uint8_t *value, size_t vlen,
+ GAttribResultFunc func,
+ gpointer user_data)
+{
+ unsigned int id;
+
+ id = gatt_write_char(attrib, handle, value, vlen, func, user_data);
+
+ queue_push_head(scan->gatt_op, UINT_TO_PTR(id));
+}
+
+static void scpp_free(struct bt_scpp *scan)
+{
+ bt_scpp_detach(scan);
+
+ g_free(scan->primary);
+ queue_destroy(scan->gatt_op, NULL); /* cleared in bt_scpp_detach */
+ g_free(scan);
+}
+
+struct bt_scpp *bt_scpp_new(void *primary)
+{
+ struct bt_scpp *scan;
+
+ scan = g_try_new0(struct bt_scpp, 1);
+ if (!scan)
+ return NULL;
+
+ scan->interval = SCAN_INTERVAL;
+ scan->window = SCAN_WINDOW;
+
+ scan->gatt_op = queue_new();
+
+ if (primary)
+ scan->primary = g_memdup(primary, sizeof(*scan->primary));
+
+ return bt_scpp_ref(scan);
+}
+
+struct bt_scpp *bt_scpp_ref(struct bt_scpp *scan)
+{
+ if (!scan)
+ return NULL;
+
+ __sync_fetch_and_add(&scan->ref_count, 1);
+
+ return scan;
+}
+
+void bt_scpp_unref(struct bt_scpp *scan)
+{
+ if (!scan)
+ return;
+
+ if (__sync_sub_and_fetch(&scan->ref_count, 1))
+ return;
+
+ scpp_free(scan);
+}
+
+static void write_scan_params(GAttrib *attrib, uint16_t handle,
+ uint16_t interval, uint16_t window)
+{
+ uint8_t value[4];
+
+ put_le16(interval, &value[0]);
+ put_le16(window, &value[2]);
+
+ gatt_write_cmd(attrib, handle, value, sizeof(value), NULL, NULL);
+}
+
+static void refresh_value_cb(const uint8_t *pdu, uint16_t len,
+ gpointer user_data)
+{
+ struct bt_scpp *scan = user_data;
+
+ DBG("Server requires refresh: %d", pdu[3]);
+
+ if (pdu[3] == SERVER_REQUIRES_REFRESH)
+ write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
+ scan->window);
+}
+
+static void ccc_written_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct bt_scpp *scan = user_data;
+
+ if (status != 0) {
+ error("Write Scan Refresh CCC failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ DBG("Scan Refresh: notification enabled");
+
+ scan->refresh_cb_id = g_attrib_register(scan->attrib,
+ ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
+ refresh_value_cb, scan, NULL);
+}
+
+static void write_ccc(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
+ void *user_data)
+{
+ uint8_t value[2];
+
+ put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+
+ write_char(scan, attrib, handle, value, sizeof(value), ccc_written_cb,
+ user_data);
+}
+
+static void discover_descriptor_cb(uint8_t status, GSList *descs,
+ void *user_data)
+{
+ struct bt_scpp *scan = user_data;
+ struct gatt_desc *desc;
+
+ if (status != 0) {
+ error("Discover descriptors failed: %s", att_ecode2str(status));
+ return;
+ }
+
+ /* There will be only one descriptor on list and it will be CCC */
+ desc = descs->data;
+
+ write_ccc(scan, scan->attrib, desc->handle, scan);
+}
+
+static void refresh_discovered_cb(uint8_t status, GSList *chars,
+ void *user_data)
+{
+ struct bt_scpp *scan = user_data;
+ struct gatt_char *chr;
+ uint16_t start, end;
+ bt_uuid_t uuid;
+
+ if (status) {
+ error("Scan Refresh %s", att_ecode2str(status));
+ return;
+ }
+
+ if (!chars) {
+ DBG("Scan Refresh not supported");
+ return;
+ }
+
+ chr = chars->data;
+
+ DBG("Scan Refresh handle: 0x%04x", chr->value_handle);
+
+ start = chr->value_handle + 1;
+ end = scan->primary->range.end;
+
+ if (start > end)
+ return;
+
+ scan->refresh_handle = chr->value_handle;
+
+ bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+ discover_desc(scan, scan->attrib, start, end, &uuid,
+ discover_descriptor_cb, user_data);
+}
+
+static void iwin_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+{
+ struct bt_scpp *scan = user_data;
+ struct gatt_char *chr;
+
+ if (status) {
+ error("Discover Scan Interval Window: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ chr = chars->data;
+ scan->iwhandle = chr->value_handle;
+
+ DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
+
+ write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
+ scan->window);
+}
+
+bool bt_scpp_attach(struct bt_scpp *scan, void *attrib)
+{
+ bt_uuid_t iwin_uuid, refresh_uuid;
+
+ if (!scan || scan->attrib || !scan->primary)
+ return false;
+
+ scan->attrib = g_attrib_ref(attrib);
+
+ if (scan->iwhandle)
+ write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
+ scan->window);
+ else {
+ bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
+ discover_char(scan, scan->attrib, scan->primary->range.start,
+ scan->primary->range.end, &iwin_uuid,
+ iwin_discovered_cb, scan);
+ }
+
+ if (scan->refresh_handle)
+ scan->refresh_cb_id = g_attrib_register(scan->attrib,
+ ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
+ refresh_value_cb, scan, NULL);
+ else {
+ bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);
+ discover_char(scan, scan->attrib, scan->primary->range.start,
+ scan->primary->range.end, &refresh_uuid,
+ refresh_discovered_cb, scan);
+ }
+
+ return true;
+}
+
+static void cancel_gatt_req(void *data, void *user_data)
+{
+ unsigned int id = PTR_TO_UINT(data);
+ struct bt_scpp *scan = user_data;
+
+ g_attrib_cancel(scan->attrib, id);
+}
+
+void bt_scpp_detach(struct bt_scpp *scan)
+{
+ if (!scan || !scan->attrib)
+ return;
+
+ if (scan->refresh_cb_id > 0) {
+ g_attrib_unregister(scan->attrib, scan->refresh_cb_id);
+ scan->refresh_cb_id = 0;
+ }
+
+ queue_foreach(scan->gatt_op, cancel_gatt_req, scan);
+ g_attrib_unref(scan->attrib);
+ scan->attrib = NULL;
+}
+
+bool bt_scpp_set_interval(struct bt_scpp *scan, uint16_t value)
+{
+ if (!scan)
+ return false;
+
+ /* TODO: Check valid range */
+
+ scan->interval = value;
+
+ return true;
+}
+
+bool bt_scpp_set_window(struct bt_scpp *scan, uint16_t value)
+{
+ if (!scan)
+ return false;
+
+ /* TODO: Check valid range */
+
+ scan->window = value;
+
+ return true;
+}
diff --git a/profiles/scanparam/scpp.h b/profiles/scanparam/scpp.h
new file mode 100644
index 00000000..048fb9f2
--- /dev/null
+++ b/profiles/scanparam/scpp.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can rescpptribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is scpptributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bt_scpp;
+
+struct bt_scpp *bt_scpp_new(void *primary);
+
+struct bt_scpp *bt_scpp_ref(struct bt_scpp *scan);
+void bt_scpp_unref(struct bt_scpp *scan);
+
+bool bt_scpp_attach(struct bt_scpp *scan, void *gatt);
+void bt_scpp_detach(struct bt_scpp *scan);
+
+bool bt_scpp_set_interval(struct bt_scpp *scan, uint16_t value);
+bool bt_scpp_set_window(struct bt_scpp *scan, uint16_t value);
diff --git a/src/adapter.c b/src/adapter.c
index 9342c67e..6571f555 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -83,6 +83,14 @@
#define ADAPTER_INTERFACE "org.bluez.Adapter1"
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+#define DEVICED_DEST "org.tizen.system.deviced"
+#define DEVICED_BATT_INTERFACE "org.tizen.system.deviced.Battery"
+#define DEVICED_BATT_OBJECT_PATH "/Org/Tizen/System/DeviceD/Battery"
+#endif /* TIZEN_WEARABLE */
+#endif
+
#define MODE_OFF 0x00
#define MODE_CONNECTABLE 0x01
#define MODE_DISCOVERABLE 0x02
@@ -92,6 +100,15 @@
#define IDLE_DISCOV_TIMEOUT (5)
#define TEMP_DEV_TIMEOUT (3 * 60)
#define BONDING_TIMEOUT (2 * 60)
+
+#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
+#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
+#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
+
+#define HCI_RSSI_INVALID 127
+#define DISTANCE_VAL_INVALID 0x7FFF
+#define PATHLOSS_MAX 137
+
#ifdef __TIZEN_PATCH__
#define check_address(address) bachk(address)
#define ADV_DATA_MAX_LENGTH 31
@@ -107,6 +124,8 @@
#define DISCOV_TYPE_LE 6
#endif /* __TIZEN_PATCH__ */
+
+
static DBusConnection *dbus_conn = NULL;
static bool kernel_conn_control = false;
@@ -122,13 +141,6 @@ static struct mgmt *mgmt_master = NULL;
static uint8_t mgmt_version = 0;
static uint8_t mgmt_revision = 0;
-#if 0 // Not used
-#ifdef __TIZEN_PATCH__
-static DBusMessage *write_sec_conn_host_support(DBusConnection *conn,
- DBusMessage *msg, void *user_data);
-#endif /* __TIZEN_PATCH__ */
-#endif
-
static GSList *adapter_drivers = NULL;
static GSList *disconnect_list = NULL;
@@ -167,10 +179,18 @@ struct conn_param {
uint16_t timeout;
};
+struct discovery_filter {
+ uint8_t type;
+ uint16_t pathloss;
+ int16_t rssi;
+ GSList *uuids;
+};
+
struct watch_client {
struct btd_adapter *adapter;
char *owner;
guint watch;
+ struct discovery_filter *discovery_filter;
};
struct service_auth {
@@ -212,6 +232,7 @@ struct btd_adapter {
bdaddr_t bdaddr; /* controller Bluetooth address */
#ifdef __TIZEN_PATCH__
+ bdaddr_t le_static_addr;
bdaddr_t rpaddr; /* controller RPA */
#endif
uint32_t dev_class; /* controller class of device */
@@ -238,13 +259,27 @@ struct btd_adapter {
bool ipsp_intialized; /* Ipsp Initialization state */
struct le_data_length_read_handler *read_handler;
struct le_data_length_read_default_data_length_handler *def_read_handler;
+#ifdef TIZEN_WEARABLE
+ guint charging_watch;
+ guint charging_timeout;
+ charging_state_e charging;
+#endif /* TIZEN_WEARABLE */
#endif
bool discovering; /* discovering property state */
+ bool filtered_discovery; /* we are doing filtered discovery */
+ bool no_scan_restart_delay; /* when this flag is set, restart scan
+ * without delay */
uint8_t discovery_type; /* current active discovery type */
uint8_t discovery_enable; /* discovery enabled/disabled */
bool discovery_suspended; /* discovery has been suspended */
GSList *discovery_list; /* list of discovery clients */
+ GSList *set_filter_list; /* list of clients that specified
+ * filter, but don't scan yet
+ */
+ /* current discovery filter, if any */
+ struct mgmt_cp_start_service_discovery *current_discovery_filter;
+
GSList *discovery_found; /* list of found devices */
guint discovery_idle_timeout; /* timeout between discovery runs */
guint passive_scan_timeout; /* timeout between passive scans */
@@ -278,7 +313,7 @@ struct btd_adapter {
uint8_t adv_tx_power;
- gboolean le_discovering; /* LE Discovery active */
+ bool le_discovering; /* LE Discovery active */
GSList *le_discovery_list; /* list of LE discovery clients */
gboolean le_auto_connect; /* LE Auto connection */
#endif
@@ -378,7 +413,8 @@ static void dev_class_changed_callback(uint16_t index, uint16_t length,
uint32_t dev_class;
if (length < sizeof(*rp)) {
- error("Wrong size of class of device changed parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of class of device changed parameters");
return;
}
@@ -401,7 +437,8 @@ static void set_dev_class_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set device class: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to set device class: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
@@ -450,7 +487,8 @@ static void set_dev_class(struct btd_adapter *adapter)
set_dev_class_complete, adapter, NULL) > 0)
return;
- error("Failed to set class of device for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id,
+ "Failed to set class of device for index %u", adapter->dev_id);
}
void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
@@ -551,6 +589,89 @@ static bool set_privacy(struct btd_adapter *adapter, bool privacy);
#endif
#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+static gboolean charging_state_timeout_cb(gpointer user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ int bredr_pkt_type = ACL_PTYPE_MASK;
+
+ adapter->charging_timeout = 0;
+
+ DBG("Set all connections to BR/EDR type");
+ g_slist_foreach(adapter->devices, device_change_pkt_type,
+ (gpointer)bredr_pkt_type);
+
+ return FALSE;
+}
+
+static void set_charging_state(struct btd_adapter *adapter,
+ charging_state_e state)
+{
+ int br_pkt_type = ACL_PTYPE_MASK |
+ HCI_2DH1 | HCI_2DH3 | HCI_2DH5 |
+ HCI_3DH1 | HCI_3DH3 | HCI_3DH5;
+
+ if (adapter->charging == state)
+ return;
+
+ DBG("old charging state : %d, new charging_state : %d",
+ adapter->charging, state);
+
+ /*
+ * Only none / wire charging <-> wireless charging state change should
+ * be handled.
+ */
+ if ((adapter->charging == NONE_CHARGING && state == WIRE_CHARGING) ||
+ (adapter->charging == WIRE_CHARGING && state == NONE_CHARGING)) {
+ DBG("Just update charging state");
+ adapter->charging = state;
+ return;
+ }
+
+ if (adapter->charging_timeout) {
+ g_source_remove(adapter->charging_timeout);
+ adapter->charging_timeout = 0;
+ }
+
+ adapter->charging = state;
+ if (adapter->charging == NONE_CHARGING ||
+ adapter->charging == WIRE_CHARGING) {
+ DBG("Trigger timeout to set connection to BR/EDR type");
+ adapter->charging_timeout = g_timeout_add(2000,
+ charging_state_timeout_cb, adapter);
+ } else if (adapter->charging == WIRELESS_CHARGING) {
+ DBG("Set all connections to BR type");
+ g_slist_foreach(adapter->devices, device_change_pkt_type,
+ (gpointer)br_pkt_type);
+ }
+
+ return;
+}
+
+static gboolean charging_state_changed(DBusConnection *connection,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ int state = 0;
+
+ DBG("charging_state_changed");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &state,
+ DBUS_TYPE_INVALID))
+ return TRUE;
+
+ set_charging_state(adapter, state);
+
+ return TRUE;
+}
+
+charging_state_e get_charging_state(struct btd_adapter *adapter)
+{
+ DBG("charging_state: %d", adapter->charging);
+ return adapter->charging;
+}
+#endif /* TIZEN_WEARABLE */
+
static int compare_slot(gconstpointer a, gconstpointer b)
{
const struct adv_info *adv = a;
@@ -597,26 +718,6 @@ static void create_advertiser(struct btd_adapter *adapter,
return;
}
-#ifndef __TIZEN_PATCH__
-/* There is no caller of this function */
-static void destroy_advertiser(struct btd_adapter *adapter,
- int slot_id)
-{
- struct adv_info *adv;
-
- if (!adapter)
- return;
-
- adv = find_advertiser(adapter, slot_id);
- if (!adv) {
- DBG("Unable to find advertiser [%d]", slot_id);
- return;
- }
-
- adapter->adv_list = g_slist_remove(adapter->adv_list,
- adv);
-}
-#endif
static void advertising_state_changed(struct btd_adapter *adapter,
int slot_id, bool enabled)
@@ -664,6 +765,36 @@ static void advertiser_cleanup(struct btd_adapter *adapter)
}
#endif
+#if defined __TIZEN_PATCH__ && defined __SPRD_PAGE_SCAN_PATCH__
+#define OCF_PAGE_SCAN_TIMEOUT 0x0018
+#define OGF_PAGE_SCAN_TIMEOUT 0x03
+
+typedef struct {
+ uint16_t timeout; /* Value */
+} __attribute__ ((packed)) hci_page_scan_timeout;
+#define HCI_PAGE_SCAN_TIMEOUT_CP_SIZE 2
+
+static gboolean send_sprd_page_scan_timeout(gint value)
+{
+ int dd;
+ hci_page_scan_timeout cp;
+ DBG("+");
+ dd = hci_open_dev(0);
+ cp.timeout = value;
+ if (hci_send_cmd(dd, OGF_PAGE_SCAN_TIMEOUT, OCF_PAGE_SCAN_TIMEOUT,
+ HCI_PAGE_SCAN_TIMEOUT_CP_SIZE, &cp) < 0) {
+ DBG("Error: While setting Page Timeout value");
+ hci_close_dev(dd);
+ return FALSE;
+ }
+ DBG("Page Scan Timeout Value Patch %d", value);
+
+ hci_close_dev(dd);
+
+ return TRUE;
+}
+#endif
+
static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
{
uint32_t changed_mask;
@@ -680,6 +811,15 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
if (adapter->current_settings & MGMT_SETTING_POWERED) {
adapter_start(adapter);
+#if defined __TIZEN_PATCH__ && defined __SPRD_PAGE_SCAN_PATCH__
+ /* Approx 6.4 Seconds of timeout */
+ /* This Added because Z3 device was not able to connect with
+ * some device as it was getting Page Timeout
+ * (LG HBS800, sony carkit) etc. So, Increasing Page timeout value
+ * from 5.12 Sec (which is default) to ~6.4sec*/
+ DBG("Setting value");
+ send_sprd_page_scan_timeout(10240);
+#endif /* __SPRD_QOS_PATCH__ */
} else {
adapter_stop(adapter);
@@ -735,7 +875,8 @@ static void new_settings_callback(uint16_t index, uint16_t length,
uint32_t settings;
if (length < sizeof(settings)) {
- error("Wrong size of new settings parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of new settings parameters");
return;
}
@@ -755,7 +896,7 @@ static void set_mode_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set mode: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
@@ -783,7 +924,8 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
set_mode_complete, adapter, NULL) > 0)
return true;
- error("Failed to set mode for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set mode for index %u",
+ adapter->dev_id);
return false;
}
@@ -813,7 +955,8 @@ static bool set_discoverable(struct btd_adapter *adapter, uint8_t mode,
set_mode_complete, adapter, NULL) > 0)
return true;
- error("Failed to set mode for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set mode for index %u",
+ adapter->dev_id);
return false;
}
@@ -851,7 +994,8 @@ static void local_name_changed_callback(uint16_t index, uint16_t length,
const struct mgmt_cp_set_local_name *rp = param;
if (length < sizeof(*rp)) {
- error("Wrong size of local name changed parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of local name changed parameters");
return;
}
@@ -905,7 +1049,8 @@ static void set_local_name_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set local name: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to set local name: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
@@ -927,7 +1072,8 @@ static int set_name(struct btd_adapter *adapter, const char *name)
strncpy(maxname, name, MAX_NAME_LENGTH);
if (!g_utf8_validate(maxname, -1, NULL)) {
- error("Name change failed: supplied name isn't valid UTF-8");
+ btd_error(adapter->dev_id,
+ "Name change failed: supplied name isn't valid UTF-8");
return -EINVAL;
}
@@ -941,7 +1087,8 @@ static int set_name(struct btd_adapter *adapter, const char *name)
set_local_name_complete, adapter, NULL) > 0)
return 0;
- error("Failed to set local name for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set local name for index %u",
+ adapter->dev_id);
return -EIO;
}
@@ -987,6 +1134,39 @@ struct btd_device *btd_adapter_find_device(struct btd_adapter *adapter,
list = g_slist_find_custom(adapter->devices, &addr,
device_addr_type_cmp);
+
+/* Find the device based on RPA */
+#ifdef __TIZEN_PATCH__
+ if (!list) {
+ uint8_t msb = 0x00;
+ char address[18];
+
+ ba2str(&addr.bdaddr, address);
+
+ msb = addr.bdaddr.b[5] >> 6;
+
+ /* Check whether address is RPA */
+ if (msb == 0x00 || msb == 0x01) {
+ list = g_slist_find_custom(adapter->devices,
+ address, (GCompareFunc) device_rpa_cmp);
+ }
+ } else {
+ device = list->data;
+
+ if (device_get_rpa_exist(device) == true) {
+ GSList *rpa_list;
+
+ rpa_list = g_slist_find_custom(adapter->devices,
+ device_get_address(device),
+ device_addr_cmp);
+ if (rpa_list) {
+ list = rpa_list;
+ bdaddr_type = BDADDR_LE_RANDOM;
+ }
+ }
+ }
+#endif
+
if (!list)
return NULL;
@@ -1040,7 +1220,7 @@ static void add_uuid_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to add UUID: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to add UUID: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
@@ -1064,7 +1244,8 @@ static int add_uuid(struct btd_adapter *adapter, uuid_t *uuid, uint8_t svc_hint)
uint128_t uint128;
if (!is_supported_uuid(uuid)) {
- warn("Ignoring unsupported UUID for addition");
+ btd_warn(adapter->dev_id,
+ "Ignoring unsupported UUID for addition");
return 0;
}
@@ -1081,7 +1262,8 @@ static int add_uuid(struct btd_adapter *adapter, uuid_t *uuid, uint8_t svc_hint)
add_uuid_complete, adapter, NULL) > 0)
return 0;
- error("Failed to add UUID for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to add UUID for index %u",
+ adapter->dev_id);
return -EIO;
}
@@ -1092,7 +1274,7 @@ static void remove_uuid_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to remove UUID: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to remove UUID: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
@@ -1116,7 +1298,8 @@ static int remove_uuid(struct btd_adapter *adapter, uuid_t *uuid)
uint128_t uint128;
if (!is_supported_uuid(uuid)) {
- warn("Ignoring unsupported UUID for removal");
+ btd_warn(adapter->dev_id,
+ "Ignoring unsupported UUID for removal");
return 0;
}
@@ -1132,7 +1315,8 @@ static int remove_uuid(struct btd_adapter *adapter, uuid_t *uuid)
remove_uuid_complete, adapter, NULL) > 0)
return 0;
- error("Failed to remove UUID for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to remove UUID for index %u",
+ adapter->dev_id);
return -EIO;
}
@@ -1143,7 +1327,7 @@ static void clear_uuids_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to clear UUIDs: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to clear UUIDs: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
@@ -1169,7 +1353,8 @@ static int clear_uuids(struct btd_adapter *adapter)
clear_uuids_complete, adapter, NULL) > 0)
return 0;
- error("Failed to clear UUIDs for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to clear UUIDs for index %u",
+ adapter->dev_id);
return -EIO;
}
@@ -1497,6 +1682,11 @@ struct btd_device *btd_adapter_get_device(struct btd_adapter *adapter,
if (!adapter)
return NULL;
+#ifdef __TIZEN_PATCH__
+ if (!bacmp(addr, BDADDR_ANY))
+ return NULL;
+#endif
+
device = btd_adapter_find_device(adapter, addr, addr_type);
if (device)
return device;
@@ -1518,7 +1708,8 @@ static void passive_scanning_complete(uint8_t status, uint16_t length,
DBG("status 0x%02x", status);
if (length < sizeof(*rp)) {
- error("Wrong size of start scanning return parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of start scanning return parameters");
return;
}
@@ -1535,7 +1726,7 @@ static gboolean passive_scanning_timeout(gpointer user_data)
adapter->passive_scan_timeout = 0;
- cp.type = (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+ cp.type = SCAN_TYPE_LE;
#ifdef __TIZEN_PATCH__
mgmt_send(adapter->mgmt, MGMT_OP_START_LE_DISCOVERY,
adapter->dev_id, sizeof(cp), &cp,
@@ -1630,7 +1821,7 @@ static void stop_passive_scanning_complete(uint8_t status, uint16_t length,
* around the time we called stop_passive_scanning().
*/
if (status != MGMT_STATUS_SUCCESS && status != MGMT_STATUS_REJECTED) {
- error("Stopping passive scanning failed: %s",
+ btd_error(adapter->dev_id, "Stopping passive scanning failed: %s",
mgmt_errstr(status));
return;
}
@@ -1646,8 +1837,8 @@ static void stop_passive_scanning_complete(uint8_t status, uint16_t length,
err = device_connect_le(dev);
if (err < 0) {
- error("LE auto connection failed: %s (%d)",
- strerror(-err), -err);
+ btd_error(adapter->dev_id, "LE auto connection failed: %s (%d)",
+ strerror(-err), -err);
trigger_passive_scanning(adapter);
}
}
@@ -1707,6 +1898,30 @@ static void cancel_passive_scanning(struct btd_adapter *adapter)
}
}
+static uint8_t get_scan_type(struct btd_adapter *adapter)
+{
+ uint8_t type;
+
+ if (adapter->current_settings & MGMT_SETTING_BREDR)
+ type = SCAN_TYPE_BREDR;
+ else
+ type = 0;
+
+ if (adapter->current_settings & MGMT_SETTING_LE)
+ type |= SCAN_TYPE_LE;
+
+ return type;
+}
+
+static void free_discovery_filter(struct discovery_filter *discovery_filter)
+{
+ if (!discovery_filter)
+ return;
+
+ g_slist_free_full(discovery_filter->uuids, g_free);
+ g_free(discovery_filter);
+}
+
static void trigger_start_discovery(struct btd_adapter *adapter, guint delay);
static void start_discovery_complete(uint8_t status, uint16_t length,
@@ -1721,7 +1936,8 @@ static void start_discovery_complete(uint8_t status, uint16_t length,
#endif
if (length < sizeof(*rp)) {
- error("Wrong size of start discovery return parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of start discovery return parameters");
return;
}
@@ -1733,7 +1949,11 @@ static void start_discovery_complete(uint8_t status, uint16_t length,
adapter->discovery_type = rp->type;
#endif
adapter->discovery_enable = 0x01;
- DBG("Discovery Type 0x%02x", adapter->discovery_type);
+
+ if (adapter->current_discovery_filter)
+ adapter->filtered_discovery = true;
+ else
+ adapter->filtered_discovery = false;
if (adapter->discovering)
return;
@@ -1769,7 +1989,6 @@ static void start_le_discovery_complete(uint8_t status, uint16_t length,
const struct mgmt_cp_start_discovery *rp = param;
DBG("status 0x%02x", status);
- DBG("Discovery Type 0x%02x", rp->type);
if (length < sizeof(*rp)) {
error("Wrong size of start discovery return parameters");
return;
@@ -1779,6 +1998,8 @@ static void start_le_discovery_complete(uint8_t status, uint16_t length,
adapter->discovery_type |= rp->type;
adapter->discovery_enable = 0x01;
+ DBG("Discovery Type 0x%02x", rp->type);
+
if (adapter->le_discovering)
return;
@@ -1788,7 +2009,7 @@ static void start_le_discovery_complete(uint8_t status, uint16_t length,
return;
} else {
- adapter->discovering = false;
+ adapter->le_discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "LEDiscovering");
@@ -1805,10 +2026,11 @@ static void start_le_discovery_complete(uint8_t status, uint16_t length,
static gboolean start_discovery_timeout(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
- struct mgmt_cp_start_discovery cp;
#ifdef __TIZEN_PATCH__
+ struct mgmt_cp_start_discovery cp;
uint8_t new_type = 0;
#else
+ struct mgmt_cp_start_service_discovery *sd_cp;
uint8_t new_type;
#endif
@@ -1839,7 +2061,6 @@ static gboolean start_discovery_timeout(gpointer user_data)
new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
}
-
if (adapter->discovery_enable == 0x01) {
/*
* If there is an already running discovery and it has the
@@ -1868,7 +2089,6 @@ static gboolean start_discovery_timeout(gpointer user_data)
return FALSE;
}
-
}
}
@@ -1886,20 +2106,25 @@ static gboolean start_discovery_timeout(gpointer user_data)
start_le_discovery_complete, adapter, NULL);
}
#else
- if (adapter->current_settings & MGMT_SETTING_BREDR)
- new_type = (1 << BDADDR_BREDR);
- else
- new_type = 0;
+ /* If we're doing filtered discovery, it must be quickly restarted */
+ adapter->no_scan_restart_delay = !!adapter->current_discovery_filter;
- if (adapter->current_settings & MGMT_SETTING_LE)
- new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+ DBG("adapter->current_discovery_filter == %d",
+ !!adapter->current_discovery_filter);
+
+ new_type = get_scan_type(adapter);
if (adapter->discovery_enable == 0x01) {
+ struct mgmt_cp_stop_discovery cp;
+
/*
- * If there is an already running discovery and it has the
- * same type, then just keep it.
+ * If we're asked to start regular discovery, and there is an
+ * already running regular discovery and it has the same type,
+ * then just keep it.
*/
- if (adapter->discovery_type == new_type) {
+ if (!adapter->current_discovery_filter &&
+ !adapter->filtered_discovery &&
+ adapter->discovery_type == new_type) {
if (adapter->discovering)
return FALSE;
@@ -1914,21 +2139,45 @@ static gboolean start_discovery_timeout(gpointer user_data)
* queue up a stop discovery command.
*
* This can happen if a passive scanning for Low Energy
- * devices is ongoing.
+ * devices is ongoing, or scan type is changed between
+ * regular and filtered, or filter was updated.
*/
cp.type = adapter->discovery_type;
-
mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
adapter->dev_id, sizeof(cp), &cp,
NULL, NULL, NULL);
+
+ /* Don't even bother to try to quickly start discovery
+ * just after stopping it, it would fail with status
+ * MGMT_BUSY. Instead discovering_callback will take
+ * care of that.
+ */
+ return FALSE;
+
}
- cp.type = new_type;
+ /* Regular discovery is required */
+ if (!adapter->current_discovery_filter) {
+ struct mgmt_cp_start_discovery cp;
- mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+ cp.type = new_type;
+ mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
adapter->dev_id, sizeof(cp), &cp,
start_discovery_complete, adapter, NULL);
-#endif //end of __TIZEN_PATCH__
+ return FALSE;
+ }
+
+ /* Filtered discovery is required */
+ sd_cp = adapter->current_discovery_filter;
+
+ DBG("sending MGMT_OP_START_SERVICE_DISCOVERY %d, %d, %d",
+ sd_cp->rssi, sd_cp->type, sd_cp->uuid_count);
+
+ mgmt_send(adapter->mgmt, MGMT_OP_START_SERVICE_DISCOVERY,
+ adapter->dev_id, sizeof(*sd_cp) + sd_cp->uuid_count * 16,
+ sd_cp, start_discovery_complete, adapter, NULL);
+
+#endif
return FALSE;
}
@@ -2107,6 +2356,7 @@ static void resume_le_discovery(struct btd_adapter *adapter)
}
#endif
#endif
+
static void discovering_callback(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
@@ -2114,22 +2364,22 @@ static void discovering_callback(uint16_t index, uint16_t length,
struct btd_adapter *adapter = user_data;
if (length < sizeof(*ev)) {
- error("Too small discovering event");
+ btd_error(adapter->dev_id, "Too small discovering event");
return;
}
- DBG("hci%u type %u discovering %u", adapter->dev_id,
- ev->type, ev->discovering);
+ DBG("hci%u type %u discovering %u method %d", adapter->dev_id, ev->type,
+ ev->discovering, adapter->filtered_discovery);
#ifdef __TIZEN_PATCH__
DBG("info discov_type %d", adapter->discovery_type);
if (ev->type == DISCOV_TYPE_BREDR) {
if (ev->discovering == FALSE) {
hci_clear_bit(BDADDR_BREDR, &adapter->discovery_type);
- adapter->discovering = FALSE;
+ adapter->discovering = false;
} else {
hci_set_bit(BDADDR_BREDR, &adapter->discovery_type);
- adapter->discovering = TRUE;
+ adapter->discovering = true;
}
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Discovering");
@@ -2138,11 +2388,11 @@ static void discovering_callback(uint16_t index, uint16_t length,
if (ev->discovering == FALSE) {
hci_clear_bit(BDADDR_LE_PUBLIC, &adapter->discovery_type);
hci_clear_bit(BDADDR_LE_RANDOM, &adapter->discovery_type);
- adapter->le_discovering = FALSE;
+ adapter->le_discovering = false;
} else {
hci_set_bit(BDADDR_LE_PUBLIC, &adapter->discovery_type);
hci_set_bit(BDADDR_LE_RANDOM, &adapter->discovery_type);
- adapter->le_discovering = TRUE;
+ adapter->le_discovering = true;
}
g_dbus_emit_property_changed(dbus_conn, adapter->path,
@@ -2155,6 +2405,7 @@ static void discovering_callback(uint16_t index, uint16_t length,
adapter->discovery_type = ev->type;
adapter->discovery_enable = ev->discovering;
#endif
+
/*
* Check for existing discoveries triggered by client applications
* and ignore all others.
@@ -2181,7 +2432,10 @@ static void discovering_callback(uint16_t index, uint16_t length,
switch (adapter->discovery_enable) {
case 0x00:
- trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
+ if (adapter->no_scan_restart_delay)
+ trigger_start_discovery(adapter, 0);
+ else
+ trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
break;
case 0x01:
@@ -2189,6 +2443,7 @@ static void discovering_callback(uint16_t index, uint16_t length,
g_source_remove(adapter->discovery_idle_timeout);
adapter->discovery_idle_timeout = 0;
}
+
break;
}
}
@@ -2205,6 +2460,8 @@ static void stop_discovery_complete(uint8_t status, uint16_t length,
adapter->discovery_type &= (~0x01);
DBG("Discovery Type 0x%02x", adapter->discovery_type);
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
adapter->discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Discovering");
@@ -2227,6 +2484,8 @@ static void stop_le_discovery_complete(uint8_t status, uint16_t length,
adapter->discovery_type &= (~0x06);
DBG("Discovery Type 0x%02x", adapter->discovery_type);
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
adapter->le_discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "LEDiscovering");
@@ -2250,8 +2509,8 @@ static void stop_discovery_complete(uint8_t status, uint16_t length,
if (status == MGMT_STATUS_SUCCESS) {
adapter->discovery_type = 0x00;
adapter->discovery_enable = 0x00;
- DBG("Discovery Type 0x%02x", adapter->discovery_type);
-
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
adapter->discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Discovering");
@@ -2270,16 +2529,18 @@ static int compare_sender(gconstpointer a, gconstpointer b)
return g_strcmp0(client->owner, sender);
}
-static void invalidate_rssi(gpointer a)
+static void invalidate_rssi_and_tx_power(gpointer a)
{
struct btd_device *dev = a;
device_set_rssi(dev, 0);
+ device_set_tx_power(dev, 127);
}
static void discovery_cleanup(struct btd_adapter *adapter)
{
- g_slist_free_full(adapter->discovery_found, invalidate_rssi);
+ g_slist_free_full(adapter->discovery_found,
+ invalidate_rssi_and_tx_power);
adapter->discovery_found = NULL;
}
@@ -2298,7 +2559,7 @@ static gboolean remove_temp_devices(gpointer user_data)
next = g_slist_next(l);
- if (device_is_temporary(dev))
+ if (device_is_temporary(dev) && !btd_device_is_connected(dev))
btd_adapter_remove_device(adapter, dev);
}
@@ -2306,6 +2567,214 @@ static gboolean remove_temp_devices(gpointer user_data)
}
#endif
+static gint g_strcmp(gconstpointer a, gconstpointer b)
+{
+ return strcmp(a, b);
+}
+
+static void extract_unique_uuids(gpointer data, gpointer user_data)
+{
+ char *uuid_str = data;
+ GSList **uuids = user_data;
+
+ if (!g_slist_find_custom(*uuids, uuid_str, g_strcmp))
+ *uuids = g_slist_insert_sorted(*uuids, uuid_str, g_strcmp);
+}
+
+/*
+ * This method merges all adapter filters into rssi, transport and uuids.
+ * Returns 1 if there was no filtered scan, 0 otherwise.
+ */
+static int merge_discovery_filters(struct btd_adapter *adapter, int *rssi,
+ uint8_t *transport, GSList **uuids)
+{
+ GSList *l;
+ bool empty_uuid = false;
+ bool has_regular_discovery = false;
+ bool has_filtered_discovery = false;
+
+ for (l = adapter->discovery_list; l != NULL; l = g_slist_next(l)) {
+ struct watch_client *client = l->data;
+ struct discovery_filter *item = client->discovery_filter;
+
+ if (!item) {
+ has_regular_discovery = true;
+ continue;
+ }
+
+ has_filtered_discovery = true;
+
+ *transport |= item->type;
+
+ /*
+ * Rule for merging rssi and pathloss into rssi field of kernel
+ * filter is as follow:
+ * - if there's any client without proximity filter, then do no
+ * proximity filtering,
+ * - if all clients specified RSSI, then use lowest value,
+ * - if any client specified pathloss, then kernel filter should
+ * do no proximity, as kernel can't compute pathloss. We'll do
+ * filtering on our own.
+ */
+ if (item->rssi == DISTANCE_VAL_INVALID)
+ *rssi = HCI_RSSI_INVALID;
+ else if (*rssi != HCI_RSSI_INVALID && *rssi >= item->rssi)
+ *rssi = item->rssi;
+ else if (item->pathloss != DISTANCE_VAL_INVALID)
+ *rssi = HCI_RSSI_INVALID;
+
+ if (!g_slist_length(item->uuids))
+ empty_uuid = true;
+
+ g_slist_foreach(item->uuids, extract_unique_uuids, uuids);
+ }
+
+ /* If no proximity filtering is set, disable it */
+ if (*rssi == DISTANCE_VAL_INVALID)
+ *rssi = HCI_RSSI_INVALID;
+
+ /*
+ * Empty_uuid variable determines wether there was any filter with no
+ * uuids. In this case someone might be looking for all devices in
+ * certain proximity, and we need to have empty uuids in kernel filter.
+ */
+ if (empty_uuid) {
+ g_slist_free(*uuids);
+ *uuids = NULL;
+ }
+
+ if (has_regular_discovery) {
+ if (!has_filtered_discovery)
+ return 1;
+
+ /*
+ * It there is both regular and filtered scan running, then
+ * clear whole fitler to report all devices.
+ */
+ *transport = get_scan_type(adapter);
+ *rssi = HCI_RSSI_INVALID;
+ g_slist_free(*uuids);
+ *uuids = NULL;
+ }
+
+ return 0;
+}
+
+static void populate_mgmt_filter_uuids(uint8_t (*mgmt_uuids)[16], GSList *uuids)
+{
+ GSList *l;
+
+ for (l = uuids; l != NULL; l = g_slist_next(l)) {
+ bt_uuid_t uuid, u128;
+ uint128_t uint128;
+
+ bt_string_to_uuid(&uuid, l->data);
+ bt_uuid_to_uuid128(&uuid, &u128);
+
+ ntoh128((uint128_t *) u128.value.u128.data, &uint128);
+ htob128(&uint128, (uint128_t *) mgmt_uuids);
+
+ mgmt_uuids++;
+ }
+}
+
+/*
+ * This method merges all adapter filters into one that will be send to kernel.
+ * cp_ptr is set to null when regular non-filtered discovery is needed,
+ * otherwise it's pointing to filter. Returns 0 on succes, -1 on error
+ */
+static int discovery_filter_to_mgmt_cp(struct btd_adapter *adapter,
+ struct mgmt_cp_start_service_discovery **cp_ptr)
+{
+ GSList *uuids = NULL;
+ struct mgmt_cp_start_service_discovery *cp;
+ int rssi = DISTANCE_VAL_INVALID;
+ int uuid_count;
+ uint8_t discovery_type = 0;
+
+ DBG("");
+
+ if (merge_discovery_filters(adapter, &rssi, &discovery_type, &uuids)) {
+ /* There are only regular scans, run just regular scan. */
+ *cp_ptr = NULL;
+ return 0;
+ }
+
+ uuid_count = g_slist_length(uuids);
+
+ cp = g_try_malloc(sizeof(*cp) + 16*uuid_count);
+ *cp_ptr = cp;
+ if (!cp) {
+ g_slist_free(uuids);
+ return -1;
+ }
+
+ cp->type = discovery_type;
+ cp->rssi = rssi;
+ cp->uuid_count = uuid_count;
+ populate_mgmt_filter_uuids(cp->uuids, uuids);
+
+ g_slist_free(uuids);
+ return 0;
+}
+
+static bool filters_equal(struct mgmt_cp_start_service_discovery *a,
+ struct mgmt_cp_start_service_discovery *b) {
+ if (!a && !b)
+ return true;
+
+ if ((!a && b) || (a && !b))
+ return false;
+
+ if (a->type != b->type)
+ return false;
+
+ if (a->rssi != b->rssi)
+ return false;
+
+ /*
+ * When we create mgmt_cp_start_service_discovery structure inside
+ * discovery_filter_to_mgmt_cp, we always keep uuids sorted, and
+ * unique, so we're safe to compare uuid_count, and uuids like that.
+ */
+ if (a->uuid_count != b->uuid_count)
+ return false;
+
+ if (memcmp(a->uuids, b->uuids, 16 * a->uuid_count) != 0)
+ return false;
+
+ return true;
+}
+
+static void update_discovery_filter(struct btd_adapter *adapter)
+{
+ struct mgmt_cp_start_service_discovery *sd_cp;
+
+ DBG("");
+
+ if (discovery_filter_to_mgmt_cp(adapter, &sd_cp)) {
+ btd_error(adapter->dev_id,
+ "discovery_filter_to_mgmt_cp returned error");
+ return;
+ }
+
+ /*
+ * If filters are equal, then don't update scan, except for when
+ * starting discovery.
+ */
+ if (filters_equal(adapter->current_discovery_filter, sd_cp) &&
+ adapter->discovering != 0) {
+ DBG("filters were equal, deciding to not restart the scan.");
+ g_free(sd_cp);
+ return;
+ }
+
+ g_free(adapter->current_discovery_filter);
+ adapter->current_discovery_filter = sd_cp;
+
+ trigger_start_discovery(adapter, 0);
+}
+
static void discovery_destroy(void *user_data)
{
struct watch_client *client = user_data;
@@ -2313,9 +2782,17 @@ static void discovery_destroy(void *user_data)
DBG("owner %s", client->owner);
+ adapter->set_filter_list = g_slist_remove(adapter->set_filter_list,
+ client);
+
adapter->discovery_list = g_slist_remove(adapter->discovery_list,
client);
+ if (client->discovery_filter) {
+ free_discovery_filter(client->discovery_filter);
+ client->discovery_filter = NULL;
+ }
+
g_free(client->owner);
g_free(client);
@@ -2351,6 +2828,33 @@ static void discovery_destroy(void *user_data)
#endif
}
+/*
+ * Returns true if client was already discovering, false otherwise. *client
+ * will point to discovering client, or client that have pre-set his filter.
+ */
+static bool get_discovery_client(struct btd_adapter *adapter,
+ const char *owner,
+ struct watch_client **client)
+{
+ GSList *list = g_slist_find_custom(adapter->discovery_list, owner,
+ compare_sender);
+ if (list) {
+ *client = list->data;
+ return true;
+ }
+
+ list = g_slist_find_custom(adapter->set_filter_list, owner,
+ compare_sender);
+ if (list) {
+ *client = list->data;
+ return false;
+ }
+
+ *client = NULL;
+ return false;
+}
+
+
#ifdef __TIZEN_PATCH__
static void le_discovery_destroy(void *user_data)
{
@@ -2402,6 +2906,9 @@ static void discovery_disconnect(DBusConnection *conn, void *user_data)
DBG("owner %s", client->owner);
+ adapter->set_filter_list = g_slist_remove(adapter->set_filter_list,
+ client);
+
adapter->discovery_list = g_slist_remove(adapter->discovery_list,
client);
@@ -2412,8 +2919,10 @@ static void discovery_disconnect(DBusConnection *conn, void *user_data)
* However in case this is the last client, the discovery in
* the kernel needs to be disabled.
*/
- if (adapter->discovery_list)
+ if (adapter->discovery_list) {
+ update_discovery_filter(adapter);
return;
+ }
/*
* In the idle phase of a discovery, there is no need to stop it
@@ -2497,43 +3006,56 @@ static DBusMessage *start_discovery(DBusConnection *conn,
struct btd_adapter *adapter = user_data;
const char *sender = dbus_message_get_sender(msg);
struct watch_client *client;
- GSList *list;
+ bool is_discovering;
DBG("sender %s", sender);
if (!(adapter->current_settings & MGMT_SETTING_POWERED))
return btd_error_not_ready(msg);
+ is_discovering = get_discovery_client(adapter, sender, &client);
+
/*
* Every client can only start one discovery, if the client
* already started a discovery then return an error.
*/
-#ifdef __TIZEN_PATCH__
- adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
-#endif
-
- list = g_slist_find_custom(adapter->discovery_list, sender,
- compare_sender);
- if (list)
+ if (is_discovering)
return btd_error_busy(msg);
+ /*
+ * If there was pre-set filter, just reconnect it to discovery_list,
+ * and trigger scan.
+ */
+ if (client) {
+ adapter->set_filter_list = g_slist_remove(
+ adapter->set_filter_list, client);
+ adapter->discovery_list = g_slist_prepend(
+ adapter->discovery_list, client);
+ update_discovery_filter(adapter);
+ return dbus_message_new_method_return(msg);
+ }
+
client = g_new0(struct watch_client, 1);
client->adapter = adapter;
client->owner = g_strdup(sender);
+ client->discovery_filter = NULL;
client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
discovery_disconnect, client,
discovery_destroy);
-
adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
client);
+#ifdef __TIZEN_PATCH__
+ adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
+#endif
+
/*
* Just trigger the discovery here. In case an already running
* discovery in idle phase exists, it will be restarted right
* away.
*/
- trigger_start_discovery(adapter, 0);
+ update_discovery_filter(adapter);
return dbus_message_new_method_return(msg);
}
@@ -2557,9 +3079,11 @@ static int set_adv_data_device_name(uint8_t *adv_data, int adv_len, char *name)
int name_len;
uint8_t *data = NULL;
- data = g_memdup(adv_data, adv_len);
+ if (!name)
+ return adv_len;
- if (!data || !name)
+ data = g_memdup(adv_data, adv_len);
+ if (!data)
return adv_len;
name_len = strlen(name);
@@ -2573,17 +3097,20 @@ static int set_adv_data_device_name(uint8_t *adv_data, int adv_len, char *name)
for (j = i; j < adv_len - 2; j++)
adv_data[j] = data[j + 2];
+ adv_data[j] = name_len + 1;
if (name_len > ADV_DATA_MAX_LENGTH - adv_len) {
+ adv_data[j] = ADV_DATA_MAX_LENGTH - adv_len + 1;
adv_data[j + 1] = EIR_NAME_SHORT;
- name_len = ADV_DATA_MAX_LENGTH - adv_len;
+ memcpy(adv_data + j + 2, name, ADV_DATA_MAX_LENGTH - adv_len);
+ g_free(data);
+ return ADV_DATA_MAX_LENGTH;
} else {
adv_data[j + 1] = EIR_NAME_COMPLETE;
+ memcpy(adv_data + j + 2, name, name_len);
+ g_free(data);
+ return adv_len + name_len;
}
- adv_data[j] = name_len + 1;
- memcpy(adv_data + j + 2, name, name_len);
- g_free(data);
- return adv_len + name_len;
} else {
memcpy(adv_data + i, &data[i], ad_len + 1);
i = i + data[i];
@@ -2629,7 +3156,8 @@ static int set_adv_data_tx_power(uint8_t *adv_data, int adv_len, int8_t tx_power
return adv_len;
}
-static gboolean adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len,
+
+int adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len,
gboolean is_scan_rsp, char *adapter_name, int8_t tx_power, uint8_t **adv_data, int *adv_len)
{
uint8_t *data;
@@ -2638,8 +3166,9 @@ static gboolean adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len
data = g_malloc0(ADV_DATA_MAX_LENGTH);
/* Fix : NULL_RETURNS */
if (data == NULL) {
- return FALSE;
+ return -1;
}
+
memcpy(data, p_data, data_len);
len = data_len;
@@ -2655,7 +3184,7 @@ static gboolean adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len
*adv_data = data;
*adv_len = len;
- return TRUE;
+ return 0;
}
static DBusMessage *adapter_start_custom_discovery(DBusConnection *conn,
@@ -2922,8 +3451,13 @@ static DBusMessage *adapter_set_advertising_params(DBusConnection *conn,
p_params->channel_map = 0x07; /* fixed channel :: will be used all */
p_params->adv_filter_policy = filter_policy;
p_params->tx_power = BLE_ADV_TX_POWER_MID; /* TODO:need to optimize */
- p_inst->bdaddr_type = 0x00;
- bacpy(&p_inst->bdaddr, &adapter->bdaddr);
+ if (adapter->le_static_addr.b[5] != 0) {
+ p_inst->bdaddr_type = 0x01;
+ bacpy(&p_inst->bdaddr, &adapter->le_static_addr);
+ } else {
+ p_inst->bdaddr_type = 0x00;
+ bacpy(&p_inst->bdaddr, &adapter->bdaddr);
+ }
ret = adapter_le_set_multi_adv_params(p_inst, p_params);
@@ -2974,9 +3508,8 @@ static DBusMessage *adapter_set_advertising_data(DBusConnection *conn,
if (len > ADV_DATA_MAX_LENGTH - 3)
return btd_error_invalid_args(msg);
- if (adapter_le_set_missed_adv_data(value, len, FALSE,
- adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
- return btd_error_failed(msg, "set advertising data failed");
+ adapter_le_set_missed_adv_data(value, len, FALSE,
+ adapter->name, adapter->adv_tx_power, &adv_data, &adv_len);
if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
if (adapter_le_set_multi_adv_data(slot_id, FALSE, adv_len, adv_data)) {
@@ -3064,10 +3597,13 @@ static DBusMessage *adapter_le_scan_filter_add_remove(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
+ struct btd_device *dev;
+ bdaddr_t bdaddr;
dbus_bool_t err;
dbus_int32_t client_if, action, filt_type, filt_index;
dbus_int32_t company_id, company_id_mask;
gchar *string;
+ char ida_string[18];
dbus_uint32_t address_type;
uint8_t *p_uuid, *p_uuid_mask, *p_data, *p_mask;
int32_t uuid_len = 0, uuid_mask_len = 0, data_len = 0, mask_len = 0;
@@ -3095,10 +3631,25 @@ static DBusMessage *adapter_le_scan_filter_add_remove(DBusConnection *conn,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
+ DBG("addr %s, type %d", string, address_type);
+
+ str2ba(string, &bdaddr);
+
+ dev = btd_adapter_find_device(adapter, &bdaddr, address_type);
+ if (dev && device_get_rpa_exist(dev) == true) {
+ ba2str(device_get_address(dev), ida_string);
+ if (btd_device_get_bdaddr_type(dev) == BDADDR_LE_PUBLIC)
+ address_type = 0x0;
+ else
+ address_type = 0x1;
+ } else {
+ memcpy(ida_string, string, sizeof(ida_string));
+ }
+
err = adapter_le_set_scan_filter_data(client_if, action, filt_type,
filt_index, company_id, company_id_mask,
uuid_len, p_uuid, uuid_mask_len, p_uuid_mask,
- string, address_type, data_len, p_data, mask_len, p_mask);
+ ida_string, address_type, data_len, p_data, mask_len, p_mask);
if (!err)
return btd_error_failed(msg, "Failed to add/remove filter");
@@ -3227,9 +3778,8 @@ static DBusMessage *adapter_set_scan_rsp_data(DBusConnection *conn,
if (len > SCAN_RESPONSE_DATA_LENGTH_MAX)
return btd_error_invalid_args(msg);
- if (adapter_le_set_missed_adv_data(value, len, TRUE,
- adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
- return btd_error_failed(msg, "set advertising data failed");
+ adapter_le_set_missed_adv_data(value, len, TRUE,
+ adapter->name, adapter->adv_tx_power, &adv_data, &adv_len);
if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
if (adapter_le_set_multi_adv_data(slot_id, TRUE, adv_len, (uint8_t *)adv_data)) {
@@ -3262,6 +3812,7 @@ static DBusMessage *adapter_add_device_white_list(DBusConnection *conn,
const gchar *address;
bdaddr_t bdaddr;
dbus_uint32_t address_type;
+ struct btd_device *dev;
DBG("Add device whie list");
if (dbus_message_get_args(msg, NULL,
@@ -3276,9 +3827,27 @@ static DBusMessage *adapter_add_device_white_list(DBusConnection *conn,
if (!(adapter->current_settings & MGMT_SETTING_POWERED))
return btd_error_not_ready(msg);
+
DBG("addr %s, type %d", address, address_type);
str2ba(address, &bdaddr);
+ dev = btd_adapter_find_device(adapter, &bdaddr, address_type);
+ if (dev && device_get_rpa_exist(dev) == true) {
+ if (adapter_le_is_supported_offloading() == FALSE) {
+ error("Spec based command is not supported yet");
+ return btd_error_not_supported(msg);
+ }
+
+ /* Add IRK value to list */
+ if (adapter_le_add_irk_to_list(device_get_irk_value(dev),
+ device_get_address(dev),
+ btd_device_get_bdaddr_type(dev))) {
+ return dbus_message_new_method_return(msg);
+ } else {
+ return btd_error_failed(msg, "Add LE IRK to list failed");
+ }
+ }
+
memset(&cp, 0, sizeof(cp));
cp.bdaddr_type = address_type;
@@ -3300,6 +3869,7 @@ static DBusMessage *adapter_remove_device_white_list(DBusConnection *conn,
const gchar *address;
bdaddr_t bdaddr;
dbus_uint32_t address_type;
+ struct btd_device *dev;
DBG("Remove device whie list");
@@ -3318,6 +3888,22 @@ static DBusMessage *adapter_remove_device_white_list(DBusConnection *conn,
DBG("addr %s, type %d", address, address_type);
str2ba(address, &bdaddr);
+ dev = btd_adapter_find_device(adapter, &bdaddr, address_type);
+ if (dev && device_get_rpa_exist(dev) == true) {
+ if (adapter_le_is_supported_offloading() == FALSE) {
+ error("Spec based command is not supported yet");
+ return btd_error_not_supported(msg);
+ }
+
+ /* Remove IRK value to list */
+ if (adapter_le_remove_irk_to_list(device_get_address(dev),
+ btd_device_get_bdaddr_type(dev))) {
+ return dbus_message_new_method_return(msg);
+ } else {
+ return btd_error_failed(msg, "Remove LE IRK to list failed");
+ }
+ }
+
memset(&cp, 0, sizeof(cp));
cp.bdaddr_type = address_type;
@@ -3379,6 +3965,140 @@ static DBusMessage *adapter_set_le_privacy(DBusConnection *conn,
return dbus_message_new_method_return(msg);
}
+static void set_le_static_address(struct btd_adapter *adapter)
+{
+ int fd;
+ int ret;
+ char address[18];
+ char dirname[PATH_MAX];
+
+ snprintf(dirname, PATH_MAX, STORAGEDIR "/%s", "le_static_addr");
+ if (access(dirname, F_OK) < 0) {
+ int i;
+ bdaddr_t le_static_addr;
+
+ le_static_addr.b[5] = adapter->bdaddr.b[5] | 0xc0;
+ for (i = 0; i < 5; i++) {
+ le_static_addr.b[i] =
+ (adapter->bdaddr.b[i] & 0x7f) << 1 |
+ (adapter->bdaddr.b[i] & 0x80) >> 7;
+ }
+
+ /*
+ * < How to get Public address from above static address >
+ *
+ * for (i = 0; i < 5; i++) {
+ * bredr_addr.b[i] =
+ * (adapter->le_static_addr.b[i] & 0xfe) >> 1 |
+ * (adapter->le_static_addr.b[i] & 0x01) << 7;
+ * }
+ * bredr_addr.b[5] = {the value from advertising data}
+ */
+
+ fd = open(dirname, O_WRONLY | O_CREAT, 0644);
+ if (fd >= 0) {
+ ba2str(&le_static_addr, address);
+ DBG("LE static random : %s", address);
+ ret = write(fd, address, strlen(address));
+ if (ret < 0) {
+ error("Cannot save LE address : %s",
+ strerror(errno));
+ }
+ close(fd);
+ } else {
+ error("Cannot save LE address");
+ }
+ bacpy(&adapter->le_static_addr, &le_static_addr);
+ } else {
+ fd = open(dirname, O_RDONLY);
+ if (fd >= 0) {
+ ret = read(fd, address, sizeof(address));
+ if (ret >= 17) {
+ /* xx:xx:xx:xx:xx:xx */
+ address[17] = '\0';
+ DBG("LE static random : %s", address);
+ str2ba(address, &adapter->le_static_addr);
+ adapter->le_static_addr.b[5] |= 0xc0;
+ } else
+ error("Invalid LE address");
+ close(fd);
+ } else {
+ error("Cannot get LE address");
+ }
+ }
+
+ return;
+}
+
+static void set_le_static_address_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+
+ DBG("index %u status 0x%02x", adapter->dev_id, status);
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ error("Failed to set static address for index %u: %s (0x%02x)",
+ adapter->dev_id, mgmt_errstr(status), status);
+ if (adapter->le_static_addr.b[5] != 0)
+ bacpy(&adapter->le_static_addr, BDADDR_ANY);
+ else
+ set_le_static_address(adapter);
+ return;
+ }
+
+ return;
+}
+
+static DBusMessage *adapter_set_le_static_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_adapter *adapter = data;
+ dbus_bool_t is_enable = FALSE;
+ struct mgmt_cp_set_static_address cp;
+
+ if (!(adapter->supported_settings & MGMT_OP_SET_STATIC_ADDRESS)) {
+ error("LE static address is not supported");
+ return btd_error_not_supported(msg);
+ }
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &is_enable,
+ DBUS_TYPE_INVALID)) {
+ error("Invalid arguments");
+ return btd_error_invalid_args(msg);
+ }
+
+ memset(&cp, 0x00, sizeof(cp));
+ if (is_enable) {
+ if (adapter->le_static_addr.b[5] != 0) {
+ DBG("LE static address is already configured");
+ return dbus_message_new_method_return(msg);
+ }
+ set_le_static_address(adapter);
+ bacpy(&cp.bdaddr, &adapter->le_static_addr);
+ } else {
+ if (adapter->le_static_addr.b[5] == 0) {
+ DBG("LE static address is not configured");
+ return dbus_message_new_method_return(msg);
+ }
+ bacpy(&adapter->le_static_addr, BDADDR_ANY);
+ }
+ DBG("Set static random address : %d", is_enable);
+
+ if (mgmt_send(mgmt_master, MGMT_OP_SET_STATIC_ADDRESS, adapter->dev_id,
+ sizeof(cp), &cp,
+ set_le_static_address_complete, adapter, NULL) <= 0) {
+ error("Failed to set static address : %d", is_enable);
+ if (is_enable)
+ bacpy(&adapter->le_static_addr, BDADDR_ANY);
+ else
+ set_le_static_address(adapter);
+ return btd_error_failed(msg, "Unable to set static address");
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
#if 0 // Not used
static void read_sec_conn_host_support_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
@@ -3568,6 +4288,7 @@ static DBusMessage *adapter_get_rssi(DBusConnection *conn,
return btd_error_failed(msg, "Get Raw RSSI Failed");
}
+#if !defined(__SPRD_PATCH__)
static void get_adv_tx_power_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -3598,6 +4319,7 @@ static void adapter_get_adv_tx_power(void *data)
get_adv_tx_power_complete, adapter, NULL);
return;
}
+#endif
#ifdef __BROADCOM_PATCH__
static DBusMessage *set_wbs_parameters(DBusConnection *conn,
@@ -4069,6 +4791,239 @@ static DBusMessage *adapter_set_manufacturer_data(DBusConnection *conn,
}
#endif /* __TIZEN_PATCH__ */
+static bool parse_uuids(DBusMessageIter *value, GSList **uuids)
+{
+ DBusMessageIter arriter;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(value, &arriter);
+ while (dbus_message_iter_get_arg_type(&arriter) != DBUS_TYPE_INVALID) {
+ bt_uuid_t uuid, u128;
+ char uuidstr[MAX_LEN_UUID_STR + 1];
+ char *uuid_param;
+
+ if (dbus_message_iter_get_arg_type(&arriter) !=
+ DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(&arriter, &uuid_param);
+
+ if (bt_string_to_uuid(&uuid, uuid_param))
+ return false;
+
+ bt_uuid_to_uuid128(&uuid, &u128);
+ bt_uuid_to_string(&u128, uuidstr, sizeof(uuidstr));
+
+ *uuids = g_slist_prepend(*uuids, strdup(uuidstr));
+
+ dbus_message_iter_next(&arriter);
+ }
+
+ return true;
+}
+
+static bool parse_rssi(DBusMessageIter *value, int16_t *rssi)
+{
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_INT16)
+ return false;
+
+ dbus_message_iter_get_basic(value, rssi);
+ /* -127 <= RSSI <= +20 (spec V4.2 [Vol 2, Part E] 7.7.65.2) */
+ if (*rssi > 20 || *rssi < -127)
+ return false;
+
+ return true;
+}
+
+static bool parse_pathloss(DBusMessageIter *value, uint16_t *pathloss)
+{
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ return false;
+
+ dbus_message_iter_get_basic(value, pathloss);
+ /* pathloss filter must be smaller that PATHLOSS_MAX */
+ if (*pathloss > PATHLOSS_MAX)
+ return false;
+
+ return true;
+}
+
+static bool parse_transport(DBusMessageIter *value, uint8_t *transport)
+{
+ char *transport_str;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(value, &transport_str);
+
+ if (!strcmp(transport_str, "bredr"))
+ *transport = SCAN_TYPE_BREDR;
+ else if (!strcmp(transport_str, "le"))
+ *transport = SCAN_TYPE_LE;
+ else if (!strcmp(transport_str, "auto"))
+ *transport = SCAN_TYPE_DUAL;
+ else
+ return false;
+
+ return true;
+}
+
+static bool parse_discovery_filter_entry(char *key, DBusMessageIter *value,
+ struct discovery_filter *filter)
+{
+ if (!strcmp("UUIDs", key))
+ return parse_uuids(value, &filter->uuids);
+
+ if (!strcmp("RSSI", key))
+ return parse_rssi(value, &filter->rssi);
+
+ if (!strcmp("Pathloss", key))
+ return parse_pathloss(value, &filter->pathloss);
+
+ if (!strcmp("Transport", key))
+ return parse_transport(value, &filter->type);
+
+ DBG("Unknown key parameter: %s!\n", key);
+ return false;
+}
+
+/*
+ * This method is responsible for parsing parameters to SetDiscoveryFilter. If
+ * filter in msg was empty, sets *filter to NULL. If whole parsing was
+ * successful, sets *filter to proper value.
+ * Returns false on any error, and true on success.
+ */
+static bool parse_discovery_filter_dict(struct discovery_filter **filter,
+ DBusMessage *msg)
+{
+ DBusMessageIter iter, subiter, dictiter, variantiter;
+ bool is_empty = true;
+
+ *filter = g_try_malloc(sizeof(**filter));
+ if (!*filter)
+ return false;
+
+ (*filter)->uuids = NULL;
+ (*filter)->pathloss = DISTANCE_VAL_INVALID;
+ (*filter)->rssi = DISTANCE_VAL_INVALID;
+ (*filter)->type = SCAN_TYPE_DUAL;
+
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)
+ goto invalid_args;
+
+ dbus_message_iter_recurse(&iter, &subiter);
+ do {
+ int type = dbus_message_iter_get_arg_type(&subiter);
+ char *key;
+
+ if (type == DBUS_TYPE_INVALID)
+ break;
+
+ is_empty = false;
+ dbus_message_iter_recurse(&subiter, &dictiter);
+
+ dbus_message_iter_get_basic(&dictiter, &key);
+ if (!dbus_message_iter_next(&dictiter))
+ goto invalid_args;
+
+ if (dbus_message_iter_get_arg_type(&dictiter) !=
+ DBUS_TYPE_VARIANT)
+ goto invalid_args;
+
+ dbus_message_iter_recurse(&dictiter, &variantiter);
+
+ if (!parse_discovery_filter_entry(key, &variantiter, *filter))
+ goto invalid_args;
+
+ dbus_message_iter_next(&subiter);
+ } while (true);
+
+ if (is_empty) {
+ g_free(*filter);
+ *filter = NULL;
+ return true;
+ }
+
+ /* only pathlos or rssi can be set, never both */
+ if ((*filter)->pathloss != DISTANCE_VAL_INVALID &&
+ (*filter)->rssi != DISTANCE_VAL_INVALID)
+ goto invalid_args;
+
+ DBG("filtered discovery params: transport: %d rssi: %d pathloss: %d",
+ (*filter)->type, (*filter)->rssi, (*filter)->pathloss);
+
+ return true;
+
+invalid_args:
+ g_slist_free_full((*filter)->uuids, g_free);
+ g_free(*filter);
+ *filter = NULL;
+ return false;
+}
+
+static DBusMessage *set_discovery_filter(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ struct watch_client *client;
+ struct discovery_filter *discovery_filter;
+ const char *sender = dbus_message_get_sender(msg);
+ bool is_discovering;
+
+ DBG("sender %s", sender);
+
+ if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+ return btd_error_not_ready(msg);
+
+ if (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 8))
+ return btd_error_not_supported(msg);
+
+ /* parse parameters */
+ if (!parse_discovery_filter_dict(&discovery_filter, msg))
+ return btd_error_invalid_args(msg);
+
+ is_discovering = get_discovery_client(adapter, sender, &client);
+
+ if (client) {
+ free_discovery_filter(client->discovery_filter);
+ client->discovery_filter = discovery_filter;
+
+ if (is_discovering)
+ update_discovery_filter(adapter);
+
+ if (discovery_filter || is_discovering)
+ return dbus_message_new_method_return(msg);
+
+ /* Removing pre-set filter */
+ adapter->set_filter_list = g_slist_remove(
+ adapter->set_filter_list,
+ client);
+ g_free(client->owner);
+ g_free(client);
+ DBG("successfully cleared pre-set filter");
+ } else if (discovery_filter) {
+ /* Client pre-setting his filter for first time */
+ client = g_new0(struct watch_client, 1);
+ client->adapter = adapter;
+ client->owner = g_strdup(sender);
+ client->discovery_filter = discovery_filter;
+ client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+ discovery_disconnect, client,
+ discovery_destroy);
+ adapter->set_filter_list = g_slist_prepend(
+ adapter->set_filter_list, client);
+
+ DBG("successfully pre-set filter");
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
static DBusMessage *stop_discovery(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -4101,12 +5056,10 @@ static DBusMessage *stop_discovery(DBusConnection *conn,
*/
g_dbus_remove_watch(dbus_conn, client->watch);
- /*
- * As long as other discovery clients are still active, just
- * return success.
- */
- if (adapter->discovery_list)
+ if (adapter->discovery_list) {
+ update_discovery_filter(adapter);
return dbus_message_new_method_return(msg);
+ }
/*
* In the idle phase of a discovery, there is no need to stop it
@@ -4145,6 +5098,38 @@ static gboolean property_get_address(const GDBusPropertyTable *property,
return TRUE;
}
+#ifdef __TIZEN_PATCH__
+static gboolean property_get_le_address(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ DBusMessageIter entry;
+ char addr[18];
+ const char *str = addr;
+ char *type = NULL;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &entry);
+
+ if (adapter->le_static_addr.b[5] != 0) {
+ ba2str(&adapter->le_static_addr, addr);
+ type = g_strdup_printf("%d", BDADDR_LE_RANDOM);
+ } else {
+ ba2str(&adapter->bdaddr, addr);
+ type = g_strdup_printf("%d", BDADDR_LE_PUBLIC);
+ }
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &type);
+ g_free((void *)type);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+ dbus_message_iter_close_container(iter, &entry);
+
+ return TRUE;
+}
+#endif
+
static gboolean property_get_name(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
{
@@ -4266,7 +5251,7 @@ static void property_set_mode_complete(uint8_t status, uint16_t length,
if (status != MGMT_STATUS_SUCCESS) {
const char *dbus_err;
- error("Failed to set mode: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
mgmt_errstr(status), status);
if (status == MGMT_STATUS_RFKILLED)
@@ -4387,7 +5372,8 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
g_free(data);
failed:
- error("Failed to set mode for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set mode for index %u",
+ adapter->dev_id);
g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
}
@@ -4636,8 +5622,8 @@ static gboolean property_get_supported_le_features(
val = g_strdup_printf("%d", value);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
- free((void *)str);
- free((void *)val);
+ g_free((void *)str);
+ g_free((void *)val);
}
value = adapter_le_is_supported_offloading();
@@ -4648,8 +5634,8 @@ static gboolean property_get_supported_le_features(
val = g_strdup_printf("%d", value);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
- free((void *)str);
- free((void *)val);
+ g_free((void *)str);
+ g_free((void *)val);
}
value = adapter_le_get_scan_filter_size();
@@ -4660,8 +5646,8 @@ static gboolean property_get_supported_le_features(
val = g_strdup_printf("%d", value);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
- free((void *)str);
- free((void *)val);
+ g_free((void *)str);
+ g_free((void *)val);
}
dbus_message_iter_close_container(iter, &entry);
@@ -4826,15 +5812,29 @@ static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
const gchar *address;
GSList *l;
const gchar *dev_path;
+ bdaddr_t rpa;
+ uint8_t msb = 0x00;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
+ str2ba(address, &rpa);
+
l = g_slist_find_custom(adapter->devices,
address, (GCompareFunc) device_address_cmp);
+
+ if (!l) {
+ msb = rpa.b[5] >> 6;
+
+ /* Check whether address is RPA */
+ if (msb == 0x00 || msb == 0x01)
+ l = g_slist_find_custom(adapter->devices,
+ address, (GCompareFunc) device_rpa_cmp);
+ }
+
if (!l)
- return btd_error_does_not_exist(msg);
+ return btd_error_does_not_exist(msg);
device = l->data;
@@ -5033,6 +6033,9 @@ static DBusMessage *remove_device(DBusConnection *conn,
static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("StartDiscovery", NULL, NULL, start_discovery) },
+ { GDBUS_METHOD("SetDiscoveryFilter",
+ GDBUS_ARGS({ "properties", "a{sv}" }), NULL,
+ set_discovery_filter) },
{ GDBUS_METHOD("StopDiscovery", NULL, NULL, stop_discovery) },
#ifdef __TIZEN_PATCH__
{ GDBUS_METHOD("StartCustomDiscovery",
@@ -5118,6 +6121,9 @@ static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("SetLePrivacy",
GDBUS_ARGS({ "enable", "b" }), NULL,
adapter_set_le_privacy) },
+ { GDBUS_METHOD("SetLeStaticRandomAddress",
+ GDBUS_ARGS({ "enable", "b" }), NULL,
+ adapter_set_le_static_address) },
{ GDBUS_ASYNC_METHOD("EnableRssi",
GDBUS_ARGS({ "bt_address", "s" },
{ "link_type", "i" },
@@ -5225,6 +6231,7 @@ static const GDBusPropertyTable adapter_properties[] = {
{ "Version", "s", property_get_version },
{ "SupportedLEFeatures", "as", property_get_supported_le_features},
{ "IpspInitStateChanged", "b", property_get_ipsp_init_state},
+ { "LEAddress", "as", property_get_le_address },
#endif
{ }
@@ -5377,9 +6384,17 @@ static struct irk_info *get_irk_info(GKeyFile *key_file, const char *peer,
char *str;
str = g_key_file_get_string(key_file, "IdentityResolvingKey", "Key", NULL);
+#ifdef __TIZEN_PATCH__
+ if (!str)
+ return NULL;
+ if (strlen(str) < 32) {
+ g_free(str);
+ return NULL;
+ }
+#else
if (!str || strlen(str) < 32)
return NULL;
-
+#endif
irk = g_new0(struct irk_info, 1);
str2ba(peer, &irk->bdaddr);
@@ -5429,7 +6444,8 @@ static void load_link_keys_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to load link keys for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to load link keys for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
return;
}
@@ -5465,7 +6481,8 @@ static void load_link_keys(struct btd_adapter *adapter, GSList *keys,
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("No memory for link keys for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No memory for link keys for hci%u",
+ adapter->dev_id);
return;
}
@@ -5497,14 +6514,16 @@ static void load_link_keys(struct btd_adapter *adapter, GSList *keys,
g_free(cp);
if (id == 0)
- error("Failed to load link keys for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to load link keys for hci%u",
+ adapter->dev_id);
}
static gboolean load_ltks_timeout(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
- error("Loading LTKs timed out for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Loading LTKs timed out for hci%u",
+ adapter->dev_id);
adapter->load_ltks_timeout = 0;
@@ -5520,7 +6539,8 @@ static void load_ltks_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to load LTKs for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to load LTKs for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
}
@@ -5560,7 +6580,8 @@ static void load_ltks(struct btd_adapter *adapter, GSList *keys)
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("No memory for LTKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No memory for LTKs for hci%u",
+ adapter->dev_id);
return;
}
@@ -5592,7 +6613,8 @@ static void load_ltks(struct btd_adapter *adapter, GSList *keys)
g_free(cp);
if (adapter->load_ltks_id == 0) {
- error("Failed to load LTKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to load LTKs for hci%u",
+ adapter->dev_id);
return;
}
@@ -5611,12 +6633,14 @@ static void load_irks_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status == MGMT_STATUS_UNKNOWN_COMMAND) {
- info("Load IRKs failed: Kernel doesn't support LE Privacy");
+ btd_info(adapter->dev_id,
+ "Load IRKs failed: Kernel doesn't support LE Privacy");
return;
}
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to load IRKs for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to load IRKs for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
return;
}
@@ -5663,7 +6687,8 @@ static void load_irks(struct btd_adapter *adapter, GSList *irks)
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("No memory for IRKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No memory for IRKs for hci%u",
+ adapter->dev_id);
return;
}
@@ -5688,7 +6713,8 @@ static void load_irks(struct btd_adapter *adapter, GSList *irks)
g_free(cp);
if (id == 0)
- error("Failed to IRKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to IRKs for hci%u",
+ adapter->dev_id);
}
static void load_conn_params_complete(uint8_t status, uint16_t length,
@@ -5697,7 +6723,8 @@ static void load_conn_params_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("hci%u Load Connection Parameters failed: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "hci%u Load Connection Parameters failed: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
return;
}
@@ -5729,7 +6756,8 @@ static void load_conn_params(struct btd_adapter *adapter, GSList *params)
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("Failed to allocate memory for connection parameters");
+ btd_error(adapter->dev_id,
+ "Failed to allocate memory for connection parameters");
return;
}
@@ -5752,7 +6780,7 @@ static void load_conn_params(struct btd_adapter *adapter, GSList *params)
g_free(cp);
if (id == 0)
- error("Load connection parameters failed");
+ btd_error(adapter->dev_id, "Load connection parameters failed");
}
static uint8_t get_le_addr_type(GKeyFile *keyfile)
@@ -5776,6 +6804,13 @@ static uint8_t get_le_addr_type(GKeyFile *keyfile)
return addr_type;
}
+static void probe_devices(void *user_data)
+{
+ struct btd_device *device = user_data;
+
+ device_probe_profiles(device, btd_device_get_uuids(device));
+}
+
static void load_devices(struct btd_adapter *adapter)
{
char dirname[PATH_MAX];
@@ -5784,6 +6819,7 @@ static void load_devices(struct btd_adapter *adapter)
GSList *ltks = NULL;
GSList *irks = NULL;
GSList *params = NULL;
+ GSList *added_devices = NULL;
DIR *dir;
struct dirent *entry;
@@ -5793,7 +6829,9 @@ static void load_devices(struct btd_adapter *adapter)
dir = opendir(dirname);
if (!dir) {
- error("Unable to open adapter storage directory: %s", dirname);
+ btd_error(adapter->dev_id,
+ "Unable to open adapter storage directory: %s",
+ dirname);
return;
}
@@ -5801,8 +6839,13 @@ static void load_devices(struct btd_adapter *adapter)
struct btd_device *device;
char filename[PATH_MAX];
GKeyFile *key_file;
+#ifdef __TIZEN_PATCH__
+ struct link_key_info *key_info = NULL;
+ GSList *list, *ltk_info = NULL;
+#else
struct link_key_info *key_info;
GSList *list, *ltk_info;
+#endif
struct irk_info *irk_info;
struct conn_param *param;
uint8_t bdaddr_type;
@@ -5813,6 +6856,18 @@ static void load_devices(struct btd_adapter *adapter)
if (entry->d_type != DT_DIR || bachk(entry->d_name) < 0)
continue;
+#ifdef __TIZEN_PATCH__
+{
+ bdaddr_t bdaddr;
+
+ str2ba(entry->d_name, &bdaddr);
+
+ if (!bacmp(&bdaddr, BDADDR_ANY)) {
+ error("No Bluetooth address");
+ continue;
+ }
+}
+#endif
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr,
entry->d_name);
@@ -5848,14 +6903,43 @@ static void load_devices(struct btd_adapter *adapter)
if (!device)
goto free;
+#ifdef __TIZEN_PATCH__
+{
+ char irk_addr[18];
+
+ /* After load IRK information from file, store it into device->bdaddr
+ RPA is stored in device->rpa_addr */
+ ba2str(device_get_address(device), irk_addr);
+
+ DBG("irk address: %s, rpa_exist %d", irk_addr, device_get_rpa_exist(device));
+
+ if (device_get_rpa_exist(device) == true) {
+ if (key_info)
+ str2ba(irk_addr, &key_info->bdaddr);
+
+ if (ltk_info) {
+ ltks = g_slist_remove(ltks, ltk_info);
+ ltk_info = get_ltk_info(key_file, irk_addr, bdaddr_type);
+ ltks = g_slist_concat(ltks, ltk_info);
+ }
+
+ if (irk_info) {
+ str2ba(irk_addr, &irk_info->bdaddr);
+ device_set_irk_value(device, irk_info->val);
+ }
+
+ if (param)
+ str2ba(irk_addr, &param->bdaddr);
+ }
+}
+#endif
+
btd_device_set_temporary(device, false);
adapter->devices = g_slist_append(adapter->devices, device);
/* TODO: register services from pre-loaded list of primaries */
- list = btd_device_get_uuids(device);
- if (list)
- device_probe_profiles(device, list);
+ added_devices = g_slist_append(added_devices, device);
device_exist:
if (key_info) {
@@ -5884,6 +6968,8 @@ free:
load_conn_params(adapter, params);
g_slist_free_full(params, g_free);
+ g_slist_free_full(added_devices, probe_devices);
+
#ifdef __TIZEN_PATCH__
load_devices_rpa_res_support(adapter);
#endif
@@ -5946,7 +7032,8 @@ static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
err = driver->probe(adapter);
if (err < 0) {
- error("%s: %s (%d)", driver->name, strerror(-err), -err);
+ btd_error(adapter->dev_id, "%s: %s (%d)", driver->name,
+ strerror(-err), -err);
return;
}
@@ -5971,7 +7058,8 @@ static void probe_profile(struct btd_profile *profile, void *data)
err = profile->adapter_probe(profile, adapter);
if (err < 0) {
- error("%s: %s (%d)", profile->name, strerror(-err), -err);
+ btd_error(adapter->dev_id, "%s: %s (%d)", profile->name,
+ strerror(-err), -err);
return;
}
@@ -6013,7 +7101,8 @@ static void adapter_add_connection(struct btd_adapter *adapter,
device_add_connection(device, bdaddr_type);
if (g_slist_find(adapter->connections, device)) {
- error("Device is already marked as connected");
+ btd_error(adapter->dev_id,
+ "Device is already marked as connected");
return;
}
@@ -6028,13 +7117,15 @@ static void get_connections_complete(uint8_t status, uint16_t length,
uint16_t i, conn_count;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to get connections: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to get connections: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
if (length < sizeof(*rp)) {
- error("Wrong size of get connections response");
+ btd_error(adapter->dev_id,
+ "Wrong size of get connections response");
return;
}
@@ -6044,7 +7135,8 @@ static void get_connections_complete(uint8_t status, uint16_t length,
if (conn_count * sizeof(struct mgmt_addr_info) +
sizeof(*rp) != length) {
- error("Incorrect packet size for get connections response");
+ btd_error(adapter->dev_id,
+ "Incorrect packet size for get connections response");
return;
}
@@ -6072,7 +7164,8 @@ static void load_connections(struct btd_adapter *adapter)
get_connections_complete, adapter, NULL) > 0)
return;
- error("Failed to get connections for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to get connections for index %u",
+ adapter->dev_id);
}
bool btd_adapter_get_pairable(struct btd_adapter *adapter)
@@ -6149,7 +7242,8 @@ int adapter_connect_list_add(struct btd_adapter *adapter,
}
if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
- error("Can't add %s to non-LE capable adapter connect list",
+ btd_error(adapter->dev_id,
+ "Can't add %s to non-LE capable adapter connect list",
device_get_path(device));
return -ENOTSUP;
}
@@ -6211,7 +7305,8 @@ static void add_whitelist_complete(uint8_t status, uint16_t length,
char addr[18];
if (length < sizeof(*rp)) {
- error("Too small Add Device complete event");
+ btd_error(adapter->dev_id,
+ "Too small Add Device complete event");
return;
}
@@ -6220,12 +7315,14 @@ static void add_whitelist_complete(uint8_t status, uint16_t length,
dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
rp->addr.type);
if (!dev) {
- error("Add Device complete for unknown device %s", addr);
+ btd_error(adapter->dev_id,
+ "Add Device complete for unknown device %s", addr);
return;
}
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to add device %s: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to add device %s: %s (0x%02x)",
addr, mgmt_errstr(status), status);
return;
}
@@ -6297,7 +7394,8 @@ static void add_device_complete(uint8_t status, uint16_t length,
char addr[18];
if (length < sizeof(*rp)) {
- error("Too small Add Device complete event");
+ btd_error(adapter->dev_id,
+ "Too small Add Device complete event");
return;
}
@@ -6306,12 +7404,14 @@ static void add_device_complete(uint8_t status, uint16_t length,
dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
rp->addr.type);
if (!dev) {
- error("Add Device complete for unknown device %s", addr);
+ btd_error(adapter->dev_id,
+ "Add Device complete for unknown device %s", addr);
return;
}
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to add device %s (%u): %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to add device %s (%u): %s (0x%02x)",
addr, rp->addr.type, mgmt_errstr(status), status);
adapter->connect_list = g_slist_remove(adapter->connect_list,
dev);
@@ -6421,16 +7521,25 @@ void adapter_auto_connect_remove(struct btd_adapter *adapter,
static void adapter_start(struct btd_adapter *adapter)
{
-#ifdef __TIZEN_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__SPRD_PATCH__)
if (adapter_le_read_ble_feature_info())
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "SupportedLEFeatures");
adapter_get_adv_tx_power(adapter);
+
+ /* By default enable offloading for testing, this should be modified */
+ if (adapter_le_is_supported_offloading())
+ adapter_le_enable_offloading(TRUE);
#endif
+#ifndef __TIZEN_PATCH__
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Powered");
+#else
+ g_dbus_emit_property_changed_full(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "Powered", 1);
+#endif
DBG("adapter %s has been enabled", adapter->path);
@@ -7462,6 +8571,14 @@ static void load_config(struct btd_adapter *adapter)
static struct btd_adapter *btd_adapter_new(uint16_t index)
{
struct btd_adapter *adapter;
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+ DBusConnection *conn = btd_get_dbus_connection();
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ int charging_state = 0;
+#endif /* TIZEN_WEARABLE */
+#endif
adapter = g_try_new0(struct btd_adapter, 1);
if (!adapter)
@@ -7508,6 +8625,38 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
#endif
adapter->auths = g_queue_new();
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+ adapter->charging_watch = g_dbus_add_signal_watch(conn, DEVICED_DEST,
+ DEVICED_BATT_OBJECT_PATH,
+ DEVICED_BATT_INTERFACE, "ChargerType",
+ charging_state_changed, adapter, NULL);
+ if (adapter->charging_watch == 0)
+ error("Cannot add signal watch for ChargerType");
+
+ msg = dbus_message_new_method_call(DEVICED_DEST,
+ DEVICED_BATT_OBJECT_PATH,
+ DEVICED_BATT_INTERFACE, "ChargerType");
+ if (msg) {
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ msg, 1000, NULL);
+ if (reply) {
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_INT32, &charging_state,
+ DBUS_TYPE_INVALID) == TRUE) {
+ set_charging_state(adapter, charging_state);
+ }
+ dbus_message_unref(reply);
+ } else {
+ error("Reply is NULL");
+ }
+ dbus_message_unref(msg);
+ } else {
+ error("Unable to create dbus message for charging state");
+ }
+#endif /* TIZEN_WEARABLE */
+#endif
+
return btd_adapter_ref(adapter);
}
@@ -7520,6 +8669,21 @@ static void adapter_remove(struct btd_adapter *adapter)
DBG("Removing adapter %s", adapter->path);
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+ if (adapter->charging_watch > 0) {
+ g_dbus_remove_watch(btd_get_dbus_connection(),
+ adapter->charging_watch);
+ adapter->charging_watch = 0;
+ }
+
+ if (adapter->charging_timeout) {
+ g_source_remove(adapter->charging_timeout);
+ adapter->charging_timeout = 0;
+ }
+#endif /* TIZEN_WEARABLE */
+#endif
+
if (adapter->discovery_idle_timeout > 0) {
g_source_remove(adapter->discovery_idle_timeout);
adapter->discovery_idle_timeout = 0;
@@ -7581,7 +8745,8 @@ static gboolean confirm_name_timeout(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
- error("Confirm name timed out for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Confirm name timed out for hci%u",
+ adapter->dev_id);
adapter->confirm_name_timeout = 0;
@@ -7597,7 +8762,8 @@ static void confirm_name_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to confirm name for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to confirm name for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
}
@@ -7627,7 +8793,9 @@ static void confirm_name(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
* cancel it to be safe here.
*/
if (adapter->confirm_name_id > 0) {
- warn("Found pending confirm name for hci%u", adapter->dev_id);
+ btd_warn(adapter->dev_id,
+ "Found pending confirm name for hci%u",
+ adapter->dev_id);
mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
}
@@ -7647,7 +8815,8 @@ static void confirm_name(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
confirm_name_complete, adapter, NULL);
if (adapter->confirm_name_id == 0) {
- error("Failed to confirm name for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to confirm name for hci%u",
+ adapter->dev_id);
return;
}
@@ -7683,6 +8852,60 @@ static void adapter_msd_notify(struct btd_adapter *adapter,
}
}
+static bool is_filter_match(GSList *discovery_filter, struct eir_data *eir_data,
+ int8_t rssi)
+{
+ GSList *l, *m;
+ bool got_match = false;
+
+ for (l = discovery_filter; l != NULL && got_match != true;
+ l = g_slist_next(l)) {
+ struct watch_client *client = l->data;
+ struct discovery_filter *item = client->discovery_filter;
+
+ /*
+ * If one of currently running scans is regular scan, then
+ * return all devices as matches
+ */
+ if (!item) {
+ got_match = true;
+ continue;
+ }
+
+ /* if someone started discovery with empty uuids, he wants all
+ * devices in given proximity.
+ */
+ if (!item->uuids)
+ got_match = true;
+ else {
+ for (m = item->uuids; m != NULL && got_match != true;
+ m = g_slist_next(m)) {
+ /* m->data contains string representation of
+ * uuid.
+ */
+ if (g_slist_find_custom(eir_data->services,
+ m->data,
+ g_strcmp) != NULL)
+ got_match = true;
+ }
+ }
+
+ if (got_match) {
+ /* we have service match, check proximity */
+ if (item->rssi == DISTANCE_VAL_INVALID ||
+ item->rssi <= rssi ||
+ item->pathloss == DISTANCE_VAL_INVALID ||
+ (eir_data->tx_power != 127 &&
+ eir_data->tx_power - rssi <= item->pathloss))
+ return true;
+
+ got_match = false;
+ }
+ }
+
+ return got_match;
+}
+
#ifdef __TIZEN_PATCH__
static void update_found_devices(struct btd_adapter *adapter,
const bdaddr_t *bdaddr,
@@ -7694,6 +8917,7 @@ static void update_found_devices(struct btd_adapter *adapter,
const bdaddr_t *bdaddr,
uint8_t bdaddr_type, int8_t rssi,
bool confirm, bool legacy,
+ bool not_connectable,
const uint8_t *data, uint8_t data_len)
#endif
{
@@ -7739,11 +8963,17 @@ static void update_found_devices(struct btd_adapter *adapter,
}
if (!dev) {
- error("Unable to create object for found device %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to create object for found device %s", addr);
eir_data_free(&eir_data);
return;
}
+#ifdef __TIZEN_PATCH__
+ if(device_get_rpa_exist(dev) == true)
+ bdaddr_type = BDADDR_LE_RANDOM;
+#endif
+
device_update_last_seen(dev, bdaddr_type);
/*
@@ -7780,30 +9010,45 @@ static void update_found_devices(struct btd_adapter *adapter,
}
#endif
+#ifdef __TIZEN_PATCH__
+ if (bdaddr_type == BDADDR_BREDR) {
+#endif
+ if (adapter->filtered_discovery &&
+ !is_filter_match(adapter->discovery_list, &eir_data, rssi)) {
+ eir_data_free(&eir_data);
+ return;
+ }
+
device_set_legacy(dev, legacy);
- device_set_rssi(dev, rssi);
+
+ if (adapter->filtered_discovery)
+ device_set_rssi_with_delta(dev, rssi, 0);
+ else
+ device_set_rssi(dev, rssi);
+
+ if (eir_data.tx_power != 127)
+ device_set_tx_power(dev, eir_data.tx_power);
+#ifdef __TIZEN_PATCH__
+ }
+#endif
if (eir_data.appearance != 0)
device_set_appearance(dev, eir_data.appearance);
/* Report an unknown name to the kernel even if there is a short name
* known, but still update the name with the known short name. */
- name_known = device_name_known(dev);
-
- if (eir_data.name && (eir_data.name_complete || !name_known))
- btd_device_device_set_name(dev, eir_data.name);
-
#ifdef __TIZEN_PATCH__
- /* As this logic, (eir_data.name_complete || !name_known) is always true.
- So some abnormal UI bug occurs. Such like complete name display and
- next time short name display.
- */
if (eir_data.name_complete)
name_known = device_name_known(dev);
else
name_known = false;
+#else
+ name_known = device_name_known(dev);
#endif
+ if (eir_data.name && (eir_data.name_complete || !name_known))
+ btd_device_device_set_name(dev, eir_data.name);
+
if (eir_data.class != 0)
device_set_class(dev, eir_data.class);
@@ -7823,11 +9068,16 @@ static void update_found_devices(struct btd_adapter *adapter,
if (bdaddr_type == BDADDR_BREDR)
device_set_manufacturer_info(dev, &eir_data);
else
- device_set_adv_report_info(dev, (void*)data, data_len, adv_type);
+ device_set_adv_report_info(dev, (void*)data, data_len, adv_type, rssi);
#endif
- if (eir_data.msd_list)
+ if (eir_data.msd_list) {
+ device_set_manufacturer_data(dev, eir_data.msd_list);
adapter_msd_notify(adapter, dev, eir_data.msd_list);
+ }
+
+ if (eir_data.sd_list)
+ device_set_service_data(dev, eir_data.sd_list);
eir_data_free(&eir_data);
@@ -7856,6 +9106,12 @@ static void update_found_devices(struct btd_adapter *adapter,
return;
connect_le:
+#ifndef __TIZEN_PATCH__
+ /* Ignore non-connectable events */
+ if (not_connectable)
+ return;
+#endif
+
/*
* If we're in the process of stopping passive scanning and
* connecting another (or maybe even the same) LE device just
@@ -7896,13 +9152,15 @@ static void device_found_callback(uint16_t index, uint16_t length,
char addr[18];
if (length < sizeof(*ev)) {
- error("Too short device found event (%u bytes)", length);
+ btd_error(adapter->dev_id,
+ "Too short device found event (%u bytes)", length);
return;
}
eir_len = btohs(ev->eir_len);
if (length != sizeof(*ev) + eir_len) {
- error("Device found event size mismatch (%u != %zu)",
+ btd_error(adapter->dev_id,
+ "Device found event size mismatch (%u != %zu)",
length, sizeof(*ev) + eir_len);
return;
}
@@ -7918,12 +9176,6 @@ static void device_found_callback(uint16_t index, uint16_t length,
DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
index, addr, ev->rssi, flags, eir_len);
-#ifndef __TIZEN_PATCH__
- /* Ignore non-connectable events for now */
- if (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE)
- return;
-#endif
-
confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
@@ -7934,6 +9186,7 @@ static void device_found_callback(uint16_t index, uint16_t length,
#else
update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
ev->rssi, confirm_name, legacy,
+ flags & MGMT_DEV_FOUND_NOT_CONNECTABLE,
eir, eir_len);
#endif
}
@@ -7971,8 +9224,8 @@ static void le_device_found_callback(uint16_t index, uint16_t length,
flags = btohl(ev->flags);
ba2str(&ev->addr.bdaddr, addr);
- DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
- index, addr, ev->rssi, flags, eir_len);
+ /*DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
+ index, addr, ev->rssi, flags, eir_len);*/
confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
@@ -7998,13 +9251,17 @@ static void adapter_remove_connection(struct btd_adapter *adapter,
DBG("");
if (!g_slist_find(adapter->connections, device)) {
- error("No matching connection for device");
+ btd_error(adapter->dev_id, "No matching connection for device");
return;
}
device_remove_connection(device, bdaddr_type);
+#ifdef __TIZEN_PATCH__
+ if (device_is_authenticating(device, bdaddr_type))
+#else
if (device_is_authenticating(device))
+#endif
device_cancel_authentication(device, TRUE);
/* If another bearer is still connected */
@@ -8041,10 +9298,10 @@ static void adapter_stop(struct btd_adapter *adapter)
cancel_passive_scanning(adapter);
- while (adapter->discovery_list) {
+ while (adapter->set_filter_list) {
struct watch_client *client;
- client = adapter->discovery_list->data;
+ client = adapter->set_filter_list->data;
/* g_dbus_remove_watch will remove the client from the
* adapter's list and free it using the discovery_destroy
@@ -8053,13 +9310,10 @@ static void adapter_stop(struct btd_adapter *adapter)
g_dbus_remove_watch(dbus_conn, client->watch);
}
- adapter->discovering = false;
-
-#ifdef __TIZEN_PATCH__
- while (adapter->le_discovery_list) {
+ while (adapter->discovery_list) {
struct watch_client *client;
- client = adapter->le_discovery_list->data;
+ client = adapter->discovery_list->data;
/* g_dbus_remove_watch will remove the client from the
* adapter's list and free it using the discovery_destroy
@@ -8068,8 +9322,12 @@ static void adapter_stop(struct btd_adapter *adapter)
g_dbus_remove_watch(dbus_conn, client->watch);
}
- adapter->le_discovering = false;
-#endif
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
+ g_free(adapter->current_discovery_filter);
+ adapter->current_discovery_filter = NULL;
+
+ adapter->discovering = false;
while (adapter->connections) {
struct btd_device *device = adapter->connections->data;
@@ -8180,21 +9438,39 @@ static gboolean process_auth_queue(gpointer user_data)
const char *dev_path;
/* Wait services to be resolved before asking authorization */
- if (auth->svc_id > 0)
+ if (auth->svc_id > 0) {
+#ifdef __TIZEN_PATCH__
+ DBG("Wait services to be resolved before asking authorization");
+#endif
return FALSE;
+ }
+#ifndef __TIZEN_PATCH__
if (device_is_trusted(device) == TRUE) {
+#else
+ if (device_is_trusted(device) == TRUE ||
+ device_is_profile_trusted(device, auth->uuid)) {
+#endif
auth->cb(NULL, auth->user_data);
goto next;
}
+#ifdef __TIZEN_PATCH__
+ /* If Profile is Blocked, Simply reject Authorization*/
+ if (device_is_profile_blocked(device, auth->uuid) == TRUE) {
+ auth->cb(&err, auth->user_data);
+ goto next;
+ }
+#endif
+
/* If agent is set authorization is already ongoing */
if (auth->agent)
return FALSE;
auth->agent = agent_get(NULL);
if (auth->agent == NULL) {
- warn("Authentication attempt without agent");
+ btd_warn(adapter->dev_id,
+ "Authentication attempt without agent");
auth->cb(&err, auth->user_data);
goto next;
}
@@ -8248,9 +9524,15 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
if (!device)
return 0;
+ if (device_is_disconnecting(device)) {
+ DBG("Authorization request while disconnecting");
+ return 0;
+ }
+
/* Device connected? */
if (!g_slist_find(adapter->connections, device))
- error("Authorization request for non-connected device!?");
+ btd_error(adapter->dev_id,
+ "Authorization request for non-connected device!?");
auth = g_try_new0(struct service_auth, 1);
if (!auth)
@@ -8510,7 +9792,8 @@ static void user_confirm_request_callback(uint16_t index, uint16_t length,
int err;
if (length < sizeof(*ev)) {
- error("Too small user confirm request event");
+ btd_error(adapter->dev_id,
+ "Too small user confirm request event");
return;
}
@@ -8520,14 +9803,20 @@ static void user_confirm_request_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
+#ifdef __TIZEN_PATCH__
+ device_set_auth_addr_type(device, ev->addr.type);
+#endif
+
err = device_confirm_passkey(device, btohl(ev->value),
ev->confirm_hint);
if (err < 0) {
- error("device_confirm_passkey: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_confirm_passkey: %s", strerror(-err));
btd_adapter_confirm_reply(adapter, &ev->addr.bdaddr,
ev->addr.type, FALSE);
}
@@ -8582,7 +9871,7 @@ static void user_passkey_request_callback(uint16_t index, uint16_t length,
int err;
if (length < sizeof(*ev)) {
- error("Too small passkey request event");
+ btd_error(adapter->dev_id, "Too small passkey request event");
return;
}
@@ -8592,13 +9881,19 @@ static void user_passkey_request_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
+#ifdef __TIZEN_PATCH__
+ device_set_auth_addr_type(device, ev->addr.type);
+#endif
+
err = device_request_passkey(device);
if (err < 0) {
- error("device_request_passkey: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_request_passkey: %s", strerror(-err));
btd_adapter_passkey_reply(adapter, &ev->addr.bdaddr,
ev->addr.type, INVALID_PASSKEY);
}
@@ -8615,7 +9910,7 @@ static void user_passkey_notify_callback(uint16_t index, uint16_t length,
int err;
if (length < sizeof(*ev)) {
- error("Too small passkey notify event");
+ btd_error(adapter->dev_id, "Too small passkey notify event");
return;
}
@@ -8625,7 +9920,8 @@ static void user_passkey_notify_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
@@ -8635,7 +9931,8 @@ static void user_passkey_notify_callback(uint16_t index, uint16_t length,
err = device_notify_passkey(device, passkey, ev->entered);
if (err < 0)
- error("device_notify_passkey: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_notify_passkey: %s", strerror(-err));
}
#ifdef __TIZEN_PATCH__
@@ -8918,7 +10215,8 @@ static void bt_6lowpan_conn_state_change_callback(uint16_t index, uint16_t lengt
gboolean connected = 0;
if (length < sizeof(*ev)) {
- error("Too small device connected event");
+ btd_error(adapter->dev_id,
+ "Too small device connected event");
return;
}
@@ -8929,7 +10227,8 @@ static void bt_6lowpan_conn_state_change_callback(uint16_t index, uint16_t lengt
device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
@@ -8950,7 +10249,8 @@ static void bt_le_data_length_changed_callback(uint16_t index, uint16_t length,
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small data length changed event");
+ btd_error(adapter->dev_id,
+ "Too small data length changed event");
return;
}
@@ -8961,13 +10261,38 @@ static void bt_le_data_length_changed_callback(uint16_t index, uint16_t length,
device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
device_le_data_length_changed(device, ev->max_tx_octets, ev->max_tx_time,
ev->max_rx_octets, ev->max_rx_time);
}
+
+static void le_conn_update_completed_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_conn_updated *ev = param;
+ struct btd_adapter *adapter = user_data;
+ struct btd_device *device;
+ char addr[18];
+ GSList *list;
+
+ if (length < sizeof(*ev)) {
+ error("Too small le conn update completed event");
+ return;
+ }
+
+ ba2str(&ev->addr.bdaddr, addr);
+ list = g_slist_find_custom(adapter->devices, addr,
+ device_address_cmp);
+ if (list) {
+ device = list->data;
+ if (device_get_conn_update_state(device))
+ device_set_conn_update_state(device, false);
+ }
+}
#endif
struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
@@ -9029,7 +10354,7 @@ static void pin_code_request_callback(uint16_t index, uint16_t length,
struct btd_adapter_pin_cb_iter *iter;
if (length < sizeof(*ev)) {
- error("Too small PIN code request event");
+ btd_error(adapter->dev_id, "Too small PIN code request event");
return;
}
@@ -9040,7 +10365,8 @@ static void pin_code_request_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
@@ -9063,7 +10389,9 @@ static void pin_code_request_callback(uint16_t index, uint16_t length,
if (display && device_is_bonding(device, NULL)) {
err = device_notify_pincode(device, ev->secure, pin);
if (err < 0) {
- error("device_notify_pin: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_notify_pin: %s",
+ strerror(-err));
btd_adapter_pincode_reply(adapter,
&ev->addr.bdaddr,
NULL, 0);
@@ -9077,7 +10405,8 @@ static void pin_code_request_callback(uint16_t index, uint16_t length,
err = device_request_pincode(device, ev->secure);
if (err < 0) {
- error("device_request_pin: %s", strerror(-err));
+ btd_error(adapter->dev_id, "device_request_pin: %s",
+ strerror(-err));
btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr, NULL, 0);
}
}
@@ -9196,7 +10525,8 @@ static gboolean pair_device_timeout(gpointer user_data)
struct pair_device_data *data = user_data;
struct btd_adapter *adapter = data->adapter;
- error("Pair device timed out for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Pair device timed out for hci%u",
+ adapter->dev_id);
adapter->pair_device_timeout = 0;
@@ -9228,7 +10558,7 @@ static void pair_device_complete(uint8_t status, uint16_t length,
* powered.
*/
if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
- error("Pair device failed: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Pair device failed: %s (0x%02x)",
mgmt_errstr(status), status);
bonding_attempt_complete(adapter, &data->bdaddr,
@@ -9237,7 +10567,7 @@ static void pair_device_complete(uint8_t status, uint16_t length,
}
if (length < sizeof(*rp)) {
- error("Too small pair device response");
+ btd_error(adapter->dev_id, "Too small pair device response");
return;
}
@@ -9249,7 +10579,8 @@ int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
uint8_t addr_type, uint8_t io_cap)
{
if (adapter->pair_device_id > 0) {
- error("Unable pair since another pairing is in progress");
+ btd_error(adapter->dev_id,
+ "Unable pair since another pairing is in progress");
return -EBUSY;
}
@@ -9291,7 +10622,8 @@ int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
free_pair_device_data);
if (id == 0) {
- error("Failed to pair %s for hci%u", addr, adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to pair %s for hci%u",
+ addr, adapter->dev_id);
free_pair_device_data(data);
return -EIO;
}
@@ -9369,19 +10701,27 @@ static void disconnect_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status == MGMT_STATUS_NOT_CONNECTED) {
- warn("Disconnecting failed: already disconnected");
+ btd_warn(adapter->dev_id,
+ "Disconnecting failed: already disconnected");
} else if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to disconnect device: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to disconnect device: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
if (length < sizeof(*rp)) {
- error("Too small device disconnect response");
+ btd_error(adapter->dev_id,
+ "Too small device disconnect response");
return;
}
+#ifdef __TIZEN_PATCH__
+ /* Use HCI error code instead of MGMT disconnection reason */
+ dev_disconnected(adapter, &rp->addr, 0x16);
+#else
dev_disconnected(adapter, &rp->addr, MGMT_DEV_DISCONN_LOCAL_HOST);
+#endif
}
int btd_adapter_disconnect_device(struct btd_adapter *adapter,
@@ -9410,7 +10750,7 @@ static void auth_failed_callback(uint16_t index, uint16_t length,
struct btd_adapter *adapter = user_data;
if (length < sizeof(*ev)) {
- error("Too small auth failed mgmt event");
+ btd_error(adapter->dev_id, "Too small auth failed mgmt event");
return;
}
@@ -9434,6 +10774,11 @@ static void store_link_key(struct btd_adapter *adapter,
ba2str(btd_adapter_get_address(adapter), adapter_addr);
ba2str(device_get_address(device), device_addr);
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true)
+ ba2str(device_get_rpa(device), device_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
device_addr);
key_file = g_key_file_new();
@@ -9456,6 +10801,28 @@ static void store_link_key(struct btd_adapter *adapter,
g_key_file_free(key_file);
}
+#ifdef __TIZEN_PATCH__
+static struct link_key_info *load_link_key(struct btd_adapter *adapter,
+ const char *peer)
+{
+ struct link_key_info *key_info;
+ GKeyFile *key_file;
+ char filename[PATH_MAX];
+ char srcaddr[18];
+
+ ba2str(&adapter->bdaddr, srcaddr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr, peer);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ key_info = get_key_info(key_file, peer);
+
+ return key_info;
+}
+#endif
+
static void new_link_key_callback(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
@@ -9466,24 +10833,27 @@ static void new_link_key_callback(uint16_t index, uint16_t length,
char dst[18];
if (length < sizeof(*ev)) {
- error("Too small new link key event");
+ btd_error(adapter->dev_id, "Too small new link key event");
return;
}
ba2str(&addr->bdaddr, dst);
- DBG("hci%u new key for %s type %u pin_len %u", adapter->dev_id,
- dst, ev->key.type, ev->key.pin_len);
+ DBG("hci%u new key for %s type %u pin_len %u store_hint %u",
+ adapter->dev_id, dst, ev->key.type, ev->key.pin_len,
+ ev->store_hint);
if (ev->key.pin_len > 16) {
- error("Invalid PIN length (%u) in new_key event",
+ btd_error(adapter->dev_id,
+ "Invalid PIN length (%u) in new_key event",
ev->key.pin_len);
return;
}
device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
@@ -9494,7 +10864,37 @@ static void new_link_key_callback(uint16_t index, uint16_t length,
key->pin_len);
device_set_bonded(device, BDADDR_BREDR);
+#if defined(__TIZEN_PATCH__) && defined(SUPPORT_LOCAL_DEVICE_A2DP_SINK)
+ } else {
+ DBG("store_hint %d", ev->store_hint);
+ btd_device_set_temporary(device, false);
+ }
+#else
+ }
+#endif
+
+ /* If BR/EDR linkkey exists in previous, update the linkkey into RPA based folder info */
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true) {
+ struct link_key_info *key_info;
+
+ key_info = load_link_key(adapter, dst);
+ if (key_info && key_info->type == 0x05) {
+ DBG("Replace linkkey!");
+
+ /* #define HCI_LK_AUTH_COMBINATION_P192 0x05
+ Replace the linkkey as the orginal one
+ */
+ store_link_key(adapter, device, key_info->key,
+ key_info->type, key_info->pin_len);
+
+ /* Delete irk based folder */
+ device_remove_stored_folder(device);
+ } else {
+ DBG("There is no original linkkey or type is not 0x05");
+ }
}
+#endif
bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
}
@@ -9563,7 +10963,7 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length,
char dst[18];
if (length < sizeof(*ev)) {
- error("Too small long term key event");
+ btd_error(adapter->dev_id, "Too small long term key event");
return;
}
@@ -9574,7 +10974,8 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
@@ -9604,9 +11005,21 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length,
ediv = le16_to_cpu(key->ediv);
rand = le64_to_cpu(key->rand);
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true) {
+ store_longtermkey(bdaddr, device_get_rpa(device),
+ key->addr.type, key->val, key->master,
+ key->type, key->enc_size, ediv, rand);
+ } else {
+ store_longtermkey(bdaddr, &key->addr.bdaddr,
+ key->addr.type, key->val, key->master,
+ key->type, key->enc_size, ediv, rand);
+ }
+#else
store_longtermkey(bdaddr, &key->addr.bdaddr,
key->addr.type, key->val, key->master,
key->type, key->enc_size, ediv, rand);
+#endif
device_set_bonded(device, addr->type);
}
@@ -9688,7 +11101,7 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
char dst[18];
if (length < sizeof(*ev)) {
- error("Too small CSRK event");
+ btd_error(adapter->dev_id, "Too small CSRK event");
return;
}
@@ -9699,7 +11112,8 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
@@ -9758,7 +11172,7 @@ static void new_irk_callback(uint16_t index, uint16_t length,
char dst[18], rpa[18];
if (length < sizeof(*ev)) {
- error("Too small New IRK event");
+ btd_error(adapter->dev_id, "Too small New IRK event");
return;
}
@@ -9768,8 +11182,27 @@ static void new_irk_callback(uint16_t index, uint16_t length,
DBG("hci%u new IRK for %s RPA %s", adapter->dev_id, dst, rpa);
if (bacmp(&ev->rpa, BDADDR_ANY)) {
+#ifdef __TIZEN_PATCH__
+ /*
+ * With new RPA, existing device can be found only when bonding is
+ * initiated from local side using remote RPA; so first find the device
+ * with RPA. If device is not found then find the device with IDA.
+ */
+
+ device = btd_adapter_find_device(adapter, &ev->rpa,
+ BDADDR_LE_RANDOM);
+ if (device == NULL)
+ device = btd_adapter_find_device(adapter, &addr->bdaddr,
+ addr->type);
+ if (device == NULL)
+ device = btd_adapter_get_device(adapter, &ev->rpa,
+ BDADDR_LE_RANDOM);
+#else
+
device = btd_adapter_get_device(adapter, &ev->rpa,
- BDADDR_LE_RANDOM);
+ BDADDR_LE_RANDOM);
+#endif
+
duplicate = btd_adapter_find_device(adapter, &addr->bdaddr,
addr->type);
if (duplicate == device)
@@ -9781,20 +11214,65 @@ static void new_irk_callback(uint16_t index, uint16_t length,
}
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
+#ifdef __TIZEN_PATCH__
+ if (bacmp(&ev->rpa, BDADDR_ANY) != 0) {
+ device_set_rpa(device, &ev->rpa);
+
+ if (duplicate)
+ device_set_rpa(duplicate, &ev->rpa);
+ }
+#endif
+
device_update_addr(device, &addr->bdaddr, addr->type);
+#ifdef __TIZEN_PATCH__
+ if (duplicate) {
+ device_merge_duplicate(device, duplicate);
+ device_set_irk_value(duplicate, irk->val);
+
+ /* If BR/EDR linkkey exists in previous, update the linkkey into RPA based folder info */
+ if (device_get_rpa_exist(device) == true) {
+ struct link_key_info *key_info;
+
+ key_info = load_link_key(adapter, dst);
+ if (key_info && key_info->type == 0x05) {
+ DBG("Add linkkey of BR/EDR");
+
+ /* #define HCI_LK_AUTH_COMBINATION_P192 0x05 */
+ store_link_key(adapter, device, key_info->key,
+ key_info->type, key_info->pin_len);
+
+ /* Delete IDA based folder */
+ device_remove_stored_folder(duplicate);
+ } else {
+ DBG("There is no original linkkey or type is not 0x05");
+ }
+ }
+ }
+#else
if (duplicate)
device_merge_duplicate(device, duplicate);
+#endif
persistent = !!ev->store_hint;
if (!persistent)
return;
+#ifdef __TIZEN_PATCH__
+ if (bacmp(&ev->rpa, BDADDR_ANY) != 0)
+ store_irk(adapter, device_get_rpa(device), addr->type, irk->val);
+ else
+ store_irk(adapter, &addr->bdaddr, addr->type, irk->val);
+
+ device_set_irk_value(device, irk->val);
+#else
store_irk(adapter, &addr->bdaddr, addr->type, irk->val);
+#endif
btd_device_set_temporary(device, false);
@@ -9854,7 +11332,8 @@ static void new_conn_param(uint16_t index, uint16_t length,
if (length < sizeof(*ev)) {
- error("Too small New Connection Parameter event");
+ btd_error(adapter->dev_id,
+ "Too small New Connection Parameter event");
return;
}
@@ -9870,7 +11349,8 @@ static void new_conn_param(uint16_t index, uint16_t length,
dev = btd_adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
if (!dev) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
@@ -9969,15 +11449,19 @@ static void read_local_oob_data_complete(uint8_t status, uint16_t length,
const uint8_t *hash, *randomizer;
if (status != MGMT_STATUS_SUCCESS) {
- error("Read local OOB data failed: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Read local OOB data failed: %s (0x%02x)",
mgmt_errstr(status), status);
hash = NULL;
randomizer = NULL;
-#ifndef __TIZEN_PATCH__
+#ifdef __TIZEN_PATCH__
+ } else if (length < 32) {
+#else
} else if (length < sizeof(*rp)) {
- error("Too small read local OOB data response");
- return;
#endif
+ btd_error(adapter->dev_id,
+ "Too small read local OOB data response");
+ return;
} else {
hash = rp->hash192;
randomizer = rp->rand192;
@@ -10106,7 +11590,8 @@ static int adapter_register(struct btd_adapter *adapter)
#endif
adapter_properties, adapter,
adapter_free)) {
- error("Adapter interface init failed on path %s",
+ btd_error(adapter->dev_id,
+ "Adapter interface init failed on path %s",
adapter->path);
g_free(adapter->path);
adapter->path = NULL;
@@ -10127,32 +11612,28 @@ static int adapter_register(struct btd_adapter *adapter)
adapter->database = btd_gatt_database_new(adapter);
if (!adapter->database) {
- error("Failed to create GATT database for adapter");
+ btd_error(adapter->dev_id,
+ "Failed to create GATT database for adapter");
adapters = g_slist_remove(adapters, adapter);
return -EINVAL;
}
+ if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+ /* Don't start advertising managers on non-LE controllers. */
+ if (adapter->supported_settings & MGMT_SETTING_LE) {
+ adapter->adv_manager =
+ btd_advertising_manager_new(adapter);
+ } else {
+ btd_info(adapter->dev_id,
+ "LEAdvertisingManager skipped, LE unavailable");
+ }
+ }
+
db = btd_gatt_database_get_db(adapter->database);
adapter->db_id = gatt_db_register(db, services_modified,
services_modified,
adapter, NULL);
-/* Disable Old GATT Server */
-#if 0
- btd_adapter_gatt_server_start(adapter);
-#endif
-
- /* Don't start advertising managers on non-LE controllers. */
- if (adapter->supported_settings & MGMT_SETTING_LE) {
- adapter->adv_manager = btd_advertising_manager_new(adapter);
-
- /* LEAdvertisingManager1 is experimental so optional */
- if (!adapter->adv_manager)
- error("Failed to register LEAdvertisingManager1 "
- "interface for adapter");
- } else {
- info("Not starting LEAdvertisingManager, LE not supported");
- }
load_config(adapter);
fix_storage(adapter);
load_drivers(adapter);
@@ -10220,7 +11701,8 @@ static void disconnected_callback(uint16_t index, uint16_t length,
uint8_t reason;
if (length < sizeof(struct mgmt_addr_info)) {
- error("Too small device disconnected event");
+ btd_error(adapter->dev_id,
+ "Too small device disconnected event");
return;
}
@@ -10244,13 +11726,13 @@ static void connected_callback(uint16_t index, uint16_t length,
bool name_known;
if (length < sizeof(*ev)) {
- error("Too small device connected event");
+ btd_error(adapter->dev_id, "Too small device connected event");
return;
}
eir_len = btohs(ev->eir_len);
if (length < sizeof(*ev) + eir_len) {
- error("Too small device connected event");
+ btd_error(adapter->dev_id, "Too small device connected event");
return;
}
@@ -10261,7 +11743,8 @@ static void connected_callback(uint16_t index, uint16_t length,
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
@@ -10296,7 +11779,7 @@ static void device_blocked_callback(uint16_t index, uint16_t length,
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small device blocked event");
+ btd_error(adapter->dev_id, "Too small device blocked event");
return;
}
@@ -10318,7 +11801,7 @@ static void device_unblocked_callback(uint16_t index, uint16_t length,
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small device unblocked event");
+ btd_error(adapter->dev_id, "Too small device unblocked event");
return;
}
@@ -10360,7 +11843,7 @@ static void connect_failed_callback(uint16_t index, uint16_t length,
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small connect failed event");
+ btd_error(adapter->dev_id, "Too small connect failed event");
return;
}
@@ -10415,6 +11898,11 @@ static void remove_keys(struct btd_adapter *adapter,
ba2str(btd_adapter_get_address(adapter), adapter_addr);
ba2str(device_get_address(device), device_addr);
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true)
+ ba2str(device_get_rpa(device), device_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
device_addr);
key_file = g_key_file_new();
@@ -10445,7 +11933,7 @@ static void unpaired_callback(uint16_t index, uint16_t length,
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small device unpaired event");
+ btd_error(adapter->dev_id, "Too small device unpaired event");
return;
}
@@ -10456,7 +11944,8 @@ static void unpaired_callback(uint16_t index, uint16_t length,
device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- warn("No device object for unpaired device %s", addr);
+ btd_warn(adapter->dev_id,
+ "No device object for unpaired device %s", addr);
return;
}
@@ -10612,7 +12101,8 @@ static int clear_devices(struct btd_adapter *adapter)
clear_devices_complete, adapter, NULL) > 0)
return 0;
- error("Failed to clear devices for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to clear devices for index %u",
+ adapter->dev_id);
return -EIO;
}
@@ -10628,18 +12118,21 @@ static void read_info_complete(uint8_t status, uint16_t length,
DBG("index %u status 0x%02x", adapter->dev_id, status);
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to read info for index %u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to read info for index %u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
goto failed;
}
if (length < sizeof(*rp)) {
- error("Too small read info complete response");
+ btd_error(adapter->dev_id,
+ "Too small read info complete response");
goto failed;
}
if (bacmp(&rp->bdaddr, BDADDR_ANY) == 0) {
- error("No Bluetooth address for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No Bluetooth address for index %u",
+ adapter->dev_id);
goto failed;
}
@@ -10681,7 +12174,8 @@ static void read_info_complete(uint8_t status, uint16_t length,
break;
case BT_MODE_BREDR:
if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) {
- error("Ignoring adapter withouth BR/EDR support");
+ btd_error(adapter->dev_id,
+ "Ignoring adapter withouth BR/EDR support");
goto failed;
}
@@ -10694,7 +12188,8 @@ static void read_info_complete(uint8_t status, uint16_t length,
break;
case BT_MODE_LE:
if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
- error("Ignoring adapter withouth LE support");
+ btd_error(adapter->dev_id,
+ "Ignoring adapter withouth LE support");
goto failed;
}
@@ -10707,6 +12202,7 @@ static void read_info_complete(uint8_t status, uint16_t length,
if (missing_settings & MGMT_SETTING_SECURE_CONN)
set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01);
+
if (main_opts.fast_conn &&
(missing_settings & MGMT_SETTING_FAST_CONNECTABLE))
set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, 0x01);
@@ -10720,7 +12216,7 @@ static void read_info_complete(uint8_t status, uint16_t length,
err = adapter_register(adapter);
if (err < 0) {
- error("Unable to register new adapter");
+ btd_error(adapter->dev_id, "Unable to register new adapter");
goto failed;
}
@@ -10883,9 +12379,9 @@ static void read_info_complete(uint8_t status, uint16_t length,
adapter, NULL);
mgmt_register(adapter->mgmt, MGMT_EV_MULTI_ADV_STATE_CHANGED,
- adapter->dev_id,
- multi_adv_state_change_callback,
- adapter, NULL);
+ adapter->dev_id,
+ multi_adv_state_change_callback,
+ adapter, NULL);
mgmt_register(adapter->mgmt, MGMT_EV_6LOWPAN_CONN_STATE_CHANGED,
adapter->dev_id,
@@ -10896,6 +12392,11 @@ static void read_info_complete(uint8_t status, uint16_t length,
adapter->dev_id,
bt_le_data_length_changed_callback,
adapter, NULL);
+
+ mgmt_register(adapter->mgmt, MGMT_EV_CONN_UPDATED,
+ adapter->dev_id,
+ le_conn_update_completed_callback,
+ adapter, NULL);
#endif
set_dev_class(adapter);
@@ -10946,13 +12447,15 @@ static void index_added(uint16_t index, uint16_t length, const void *param,
adapter = btd_adapter_lookup(index);
if (adapter) {
- warn("Ignoring index added for an already existing adapter");
+ btd_warn(adapter->dev_id,
+ "Ignoring index added for an already existing adapter");
return;
}
adapter = btd_adapter_new(index);
if (!adapter) {
- error("Unable to create new adapter for index %u", index);
+ btd_error(adapter->dev_id,
+ "Unable to create new adapter for index %u", index);
return;
}
@@ -10975,7 +12478,8 @@ static void index_added(uint16_t index, uint16_t length, const void *param,
read_info_complete, adapter, NULL) > 0)
return;
- error("Failed to read controller info for index %u", index);
+ btd_error(adapter->dev_id,
+ "Failed to read controller info for index %u", index);
adapter_list = g_list_remove(adapter_list, adapter);
diff --git a/src/adapter.h b/src/adapter.h
index e081604d..ee28c0f8 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -68,6 +68,16 @@ struct oob_handler {
void *user_data;
};
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+typedef enum {
+ NONE_CHARGING,
+ WIRE_CHARGING,
+ WIRELESS_CHARGING,
+} charging_state_e;
+#endif /* TIZEN_WEARABLE */
+#endif
+
int adapter_init(void);
void adapter_cleanup(void);
void adapter_shutdown(void);
@@ -304,4 +314,7 @@ struct le_data_length_read_default_data_length_handler {
int btd_adapter_le_set_data_length(struct btd_adapter *adapter, bdaddr_t *bdaddr,
uint16_t max_tx_octets, uint16_t max_tx_time);
+#ifdef TIZEN_WEARABLE
+charging_state_e get_charging_state(struct btd_adapter *adapter);
+#endif /* TIZEN_WEARABLE */
#endif
diff --git a/src/adapter_le_vsc_features.c b/src/adapter_le_vsc_features.c
index 440938c1..d6a68f80 100644
--- a/src/adapter_le_vsc_features.c
+++ b/src/adapter_le_vsc_features.c
@@ -1,5 +1,4 @@
#ifdef __TIZEN_PATCH__
-#ifdef __BROADCOM_PATCH__
#include <errno.h>
@@ -12,16 +11,6 @@
static apater_le_vsc_rp_get_vendor_cap ble_vsc_cb = { -1, };
-void add_data_to_stream(uint8_t *stream, uint8_t *data, uint8_t len)
-{
- int i;
-
- for (i=0; i<len; i++) {
- *(stream)++ = (uint8_t) data[len-1-i];
- DBG("[%d]>> 0x%X", i, data[len-1-i] );
- }
-}
-
static int send_vsc_command(uint16_t ocf, uint8_t *cp, uint8_t cp_len,
uint8_t *rp, uint8_t rp_len)
{
@@ -354,10 +343,10 @@ gboolean adapter_le_service_uuid_scan_filtering(gboolean is_solicited,
cp.action= params ->action;
cp.filter_index = params->filter_index;
- add_data_to_stream((uint8_t *)&cp.data, params->uuid, params->uuid_len);
+ memcpy(&cp.data, params->uuid, params->uuid_len);
cp_len += params->uuid_len;
- add_data_to_stream(p+params->uuid_len, params->uuid_mask, params->uuid_len);
+ memcpy(p + params->uuid_len, params->uuid_mask, params->uuid_len);
cp_len += params->uuid_len;
ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, cp_len,
@@ -435,15 +424,15 @@ gboolean adapter_le_manf_data_scan_filtering (adapter_le_manf_data_params_t *par
cp.filter_index = params->filter_index;
/* add company_id and data */
- cp.data[data_len++] = (uint8_t) (params->company_id >> 8);
cp.data[data_len++] = (uint8_t) params->company_id;
+ cp.data[data_len++] = (uint8_t) (params->company_id >> 8);
DBG("");
memcpy(p + data_len, params->man_data, params->man_data_len);
data_len += params->man_data_len;
/* add company_id mask and data mask */
- cp.data[data_len++] = (uint8_t) (params->company_id_mask >> 8);
cp.data[data_len++] = (uint8_t) params->company_id_mask;
+ cp.data[data_len++] = (uint8_t) (params->company_id_mask >> 8);
memcpy(p + data_len, params->man_data_mask, params->man_data_len);
data_len += params->man_data_len;
@@ -648,5 +637,98 @@ gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index)
return TRUE;
}
-#endif /* __BROADCOM_PATCH__ */
+gboolean adapter_le_enable_offloading(gboolean enable)
+{
+ int ret;
+ adapter_le_vsc_cp_enable_rpa_offload cp;
+ adapter_le_vsc_rp_enable_rpa_offload rp;
+
+ DBG("");
+
+ memset(&cp, 0, sizeof(cp));
+ cp.subcode = SUB_CMD_LE_ENABLE_OFFLOADING;
+ cp.enable = enable;
+
+ ret = send_vsc_command(OCF_BCM_LE_RPA_OFFLOAD, (uint8_t *) &cp, sizeof(cp),
+ (uint8_t *) &rp, sizeof(rp));
+
+ if (ret < 0)
+ return FALSE;
+
+ if (HCI_SUCCESS != rp.status) {
+ DBG("Fail to send VSC :: sub[%x] - status [0x%02x]", rp.subcode, rp.status);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean adapter_le_add_irk_to_list(uint8_t *le_irk, const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+ int ret;
+ adapter_le_vsc_cp_add_irk_to_list cp;
+ adapter_le_vsc_rp_irk_to_list rp;
+
+ DBG("addr_type %d, irk %x %x %x...", bdaddr_type, le_irk[0], le_irk[1], le_irk[2]);
+
+ memset(&cp, 0, sizeof(cp));
+ cp.subcode = SUB_CMD_LE_ADD_IRK_TO_LIST;
+ memcpy(&cp.le_irk, le_irk, sizeof(cp.le_irk));
+ bacpy(&cp.bdaddr, bdaddr);
+
+ if (bdaddr_type == BDADDR_LE_PUBLIC)
+ cp.bdaddr_type = 0x0;
+ else
+ cp.bdaddr_type = 0x1;
+
+ ret = send_vsc_command(OCF_BCM_LE_RPA_OFFLOAD, (uint8_t *) &cp, sizeof(cp),
+ (uint8_t *) &rp, sizeof(rp));
+
+ if (ret < 0)
+ return FALSE;
+
+ if (HCI_SUCCESS != rp.status) {
+ DBG("Fail to send VSC :: sub[%x] - status [0x%02x]", rp.subcode, rp.status);
+ return FALSE;
+ }
+
+ DBG("Add IRK to VCS :: available space[%d]", rp.available_space);
+
+ return TRUE;
+}
+
+gboolean adapter_le_remove_irk_to_list(const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+ int ret;
+ adapter_le_vsc_cp_remove_irk_to_list cp;
+ adapter_le_vsc_rp_irk_to_list rp;
+
+ DBG("");
+
+ memset(&cp, 0, sizeof(cp));
+ cp.subcode = SUB_CMD_LE_REMOVE_IRK_TO_LIST;
+ bacpy(&cp.bdaddr, bdaddr);
+
+ if (bdaddr_type == BDADDR_LE_PUBLIC)
+ cp.bdaddr_type = 0x0;
+ else
+ cp.bdaddr_type = 0x1;
+
+ ret = send_vsc_command(OCF_BCM_LE_RPA_OFFLOAD, (uint8_t *) &cp, sizeof(cp),
+ (uint8_t *) &rp, sizeof(rp));
+
+ if (ret < 0)
+ return FALSE;
+
+ if (HCI_SUCCESS != rp.status) {
+ DBG("Fail to send VSC :: sub[%x] - status [0x%02x]", rp.subcode, rp.status);
+ return FALSE;
+ }
+
+ DBG("Remove IRK to VCS :: available space[%d]", rp.available_space);
+
+ return TRUE;
+}
+
+
#endif /* __TIZEN_PATCH__ */
diff --git a/src/adapter_le_vsc_features.h b/src/adapter_le_vsc_features.h
index 6850e017..e5ec624a 100644
--- a/src/adapter_le_vsc_features.h
+++ b/src/adapter_le_vsc_features.h
@@ -128,8 +128,6 @@ typedef struct {
uint8_t service_data_len;
}adapter_le_service_data_params_t;
-#ifdef __BROADCOM_PATCH__
-
/*****************************************************************************
** Defentions for HCI Error Codes that are past in the events
*/
@@ -167,7 +165,15 @@ typedef struct {
#define SUB_CMD_LE_META_PF_SRVC_DATA 0x07
#define SUB_CMD_LE_META_PF_ALL 0x08
+/* Offloaded resolution of private address */
+#define OCF_BCM_LE_RPA_OFFLOAD 0x0155 /* RPA Offload OCF */
+/* subcode for rpa offloading feature */
+#define SUB_CMD_LE_ENABLE_OFFLOADING 0x01
+#define SUB_CMD_LE_ADD_IRK_TO_LIST 0x02
+#define SUB_CMD_LE_REMOVE_IRK_TO_LIST 0x03
+#define SUB_CMD_LE_CLEAR_IRK_TO_LIST 0x04
+#define SUB_CMD_LE_READ_IRK_TO_LIST 0x05
/*****************************************************************************
** CP & RP for OCF_BCM_LE_GET_VENDOR_CAP
@@ -386,6 +392,66 @@ typedef struct {
} __attribute__ ((packed)) adapter_le_vsc_rp_apcf_set_scan_filter;
+/*****************************************************************************
+** CP & RP for OCF_BCM_LE_RPA_OFFLOAD
+**
+*/
+
+/**
+*
+* CP for SUB_CMD_ENABLE_RPA_OFFLOAD
+*
+* (1 octet) subcode : SUB_CMD_ENABLE_RPA_OFFLOAD (0x01)
+* (2 octet) enable : When set to 1, it means enable, otherwise disable.
+*/
+typedef struct {
+ uint8_t subcode;
+ uint8_t enable;
+} __attribute__ ((packed)) adapter_le_vsc_cp_enable_rpa_offload;
+
+/* RP for SUB_CMD_ENABLE_RPA_OFFLOAD */
+typedef struct {
+ uint8_t status;
+ uint8_t subcode;
+} __attribute__ ((packed)) adapter_le_vsc_rp_enable_rpa_offload;
+
+/**
+*
+* CP for SUB_CMD_ADD_IRK_TO_LIST
+*
+* (1 octet) subcode : SUB_CMD_ADD_IRK_TO_LIST (0x02)
+* (16 octet) le_irk : LE IRK (1st byte LSB)
+* (1 octet) bdaddr_type : per spec
+* (6 octet) bdaddr : per spec
+*/
+typedef struct {
+ uint8_t subcode;
+ uint8_t le_irk[16];
+ uint8_t bdaddr_type;
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) adapter_le_vsc_cp_add_irk_to_list;
+
+/**
+*
+* CP for SUB_CMD_REMOVE_IRK_TO_LIST
+*
+* (1 octet) subcode : SUB_CMD_REMOVE_IRK_TO_LIST (0x03)
+* (16 octet) le_irk : LE IRK (1st byte LSB)
+* (1 octet) bdaddr_type : per spec
+* (6 octet) bdaddr : per spec
+*/
+typedef struct {
+ uint8_t subcode;
+ uint8_t bdaddr_type;
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) adapter_le_vsc_cp_remove_irk_to_list;
+
+/* RP for SUB_CMD_ADD_IRK_TO_LIST & SUB_CMD_REMOVE_IRK_TO_LIST */
+typedef struct {
+ uint8_t status;
+ uint8_t subcode;
+ uint8_t available_space;
+} __attribute__ ((packed)) adapter_le_vsc_rp_irk_to_list;
/*****************************************************************************
@@ -427,35 +493,11 @@ gboolean adapter_le_set_scan_filter_data(int client_if, int action,
int data_len, uint8_t *p_data,
int mask_len, uint8_t *p_mask);
gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index);
-#else /* __BROADCOM_PATCH__ */
-gboolean adapter_le_read_ble_feature_info(void) { return FALSE; }
-gboolean adapter_le_is_supported_multi_advertising(void) { return FALSE; }
-gboolean adapter_le_is_supported_offloading(void) { return FALSE; }
-int adapter_le_get_max_adv_instance(void) { return 0; }
-int adapter_le_get_scan_filter_size(void) { return 0; }
+gboolean adapter_le_enable_offloading(gboolean enable);
-gboolean adapter_le_set_multi_adv_params (adapter_le_adv_inst_info_t *p_inst,
- adapter_le_adv_param_t *p_params) { return FALSE; }
-gboolean adapter_le_set_multi_adv_data(uint8_t inst_id, gboolean is_scan_rsp,
- uint8_t data_len, uint8_t *p_data) { return FALSE; }
-gboolean adapter_le_enable_multi_adv (gboolean enable, uint8_t inst_id)
- { return FALSE; }
+gboolean adapter_le_add_irk_to_list(uint8_t *le_irk, const bdaddr_t *bdaddr, uint8_t bdaddr_type);
+
+gboolean adapter_le_remove_irk_to_list(const bdaddr_t *bdaddr, uint8_t bdaddr_type);
-gboolean adapter_le_enable_scan_filtering (gboolean enable) { return FALSE; }
-gboolean adapter_le_set_scan_filter_params(adapter_le_scan_filter_param_t *params)
- { return FALSE; }
-gboolean adapter_le_set_scan_filter_data(int client_if, int action,
- int filt_type, int filter_index,
- int company_id,
- int company_id_mask,
- int uuid_len, uint8_t *p_uuid,
- int uuid_mask_len, uint8_t *p_uuid_mask,
- gchar *string, int addr_type,
- int data_len, uint8_t *p_data,
- int mask_len, uint8_t *p_mask)
- { return FALSE; }
-gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index)
- { return FALSE; }
-#endif /* __BROADCOM_PATCH__ */
#endif /* __TIZEN_PATCH__ */
diff --git a/src/advertising.c b/src/advertising.c
index 04492f7a..59c8c3d8 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -26,12 +26,15 @@
#include <gdbus/gdbus.h>
#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
#include "lib/sdp.h"
#include "adapter.h"
#include "dbus-common.h"
#include "error.h"
#include "log.h"
+#include "src/shared/ad.h"
+#include "src/shared/mgmt.h"
#include "src/shared/queue.h"
#include "src/shared/util.h"
@@ -41,6 +44,11 @@
struct btd_advertising {
struct btd_adapter *adapter;
struct queue *ads;
+ struct mgmt *mgmt;
+ uint16_t mgmt_index;
+ uint8_t max_adv_len;
+ uint8_t max_ads;
+ unsigned int instance_bitmap;
};
#define AD_TYPE_BROADCAST 0
@@ -54,14 +62,28 @@ struct advertisement {
GDBusProxy *proxy;
DBusMessage *reg;
uint8_t type; /* Advertising type */
+ bool include_tx_power;
+ struct bt_ad *data;
+ uint8_t instance;
};
-static bool match_advertisement_path(const void *a, const void *b)
+struct dbus_obj_match {
+ const char *owner;
+ const char *path;
+};
+
+static bool match_advertisement(const void *a, const void *b)
{
const struct advertisement *ad = a;
- const char *path = b;
+ const struct dbus_obj_match *match = b;
+
+ if (match->owner && g_strcmp0(ad->owner, match->owner))
+ return false;
+
+ if (match->path && g_strcmp0(ad->path, match->path))
+ return false;
- return g_strcmp0(ad->path, path);
+ return true;
}
static void advertisement_free(void *data)
@@ -73,8 +95,9 @@ static void advertisement_free(void *data)
g_dbus_client_unref(ad->client);
}
- if (ad->proxy)
- g_dbus_proxy_unref(ad->proxy);
+ bt_ad_unref(ad->data);
+
+ g_dbus_proxy_unref(ad->proxy);
if (ad->owner)
g_free(ad->owner);
@@ -120,13 +143,20 @@ static void advertisement_destroy(void *data)
static void advertisement_remove(void *data)
{
struct advertisement *ad = data;
+ struct mgmt_cp_remove_advertising cp;
g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
- /* TODO: mgmt API call to remove advert */
+ cp.instance = ad->instance;
+
+ mgmt_send(ad->manager->mgmt, MGMT_OP_REMOVE_ADVERTISING,
+ ad->manager->mgmt_index, sizeof(cp), &cp, NULL, NULL,
+ NULL);
queue_remove(ad->manager->ads, ad);
+ util_clear_uid(&ad->manager->instance_bitmap, ad->instance);
+
g_idle_add(advertisement_free_idle_cb, ad);
}
@@ -163,46 +193,388 @@ static bool parse_advertising_type(GDBusProxy *proxy, uint8_t *type)
return false;
}
-static void refresh_advertisement(struct advertisement *ad)
+static bool parse_advertising_service_uuids(GDBusProxy *proxy,
+ struct bt_ad *data)
{
- DBG("Refreshing advertisement: %s", ad->path);
+ DBusMessageIter iter, ariter;
+
+ if (!g_dbus_proxy_get_property(proxy, "ServiceUUIDs", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&iter, &ariter);
+
+ bt_ad_clear_service_uuid(data);
+
+ while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
+ const char *uuid_str;
+ bt_uuid_t uuid;
+
+ dbus_message_iter_get_basic(&ariter, &uuid_str);
+
+ DBG("Adding ServiceUUID: %s", uuid_str);
+
+ if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+ goto fail;
+
+ if (!bt_ad_add_service_uuid(data, &uuid))
+ goto fail;
+
+ dbus_message_iter_next(&ariter);
+ }
+
+ return true;
+
+fail:
+ bt_ad_clear_service_uuid(data);
+ return false;
}
-static bool parse_advertisement(struct advertisement *ad)
+static bool parse_advertising_solicit_uuids(GDBusProxy *proxy,
+ struct bt_ad *data)
{
- if (!parse_advertising_type(ad->proxy, &ad->type)) {
- error("Failed to read \"Type\" property of advertisement");
+ DBusMessageIter iter, ariter;
+
+ if (!g_dbus_proxy_get_property(proxy, "SolicitUUIDs", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&iter, &ariter);
+
+ bt_ad_clear_solicit_uuid(data);
+
+ while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
+ const char *uuid_str;
+ bt_uuid_t uuid;
+
+ dbus_message_iter_get_basic(&ariter, &uuid_str);
+
+ DBG("Adding SolicitUUID: %s", uuid_str);
+
+ if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+ goto fail;
+
+ if (!bt_ad_add_solicit_uuid(data, &uuid))
+ goto fail;
+
+ dbus_message_iter_next(&ariter);
+ }
+
+ return true;
+
+fail:
+ bt_ad_clear_solicit_uuid(data);
+ return false;
+}
+
+static bool parse_advertising_manufacturer_data(GDBusProxy *proxy,
+ struct bt_ad *data)
+{
+ DBusMessageIter iter, entries;
+
+ if (!g_dbus_proxy_get_property(proxy, "ManufacturerData", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&iter, &entries);
+
+ bt_ad_clear_manufacturer_data(data);
+
+ while (dbus_message_iter_get_arg_type(&entries)
+ == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter value, entry;
+ uint16_t manuf_id;
+ uint8_t *manuf_data;
+ int len;
+
+ dbus_message_iter_recurse(&entries, &entry);
+ dbus_message_iter_get_basic(&entry, &manuf_id);
+
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
+ goto fail;
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
+ goto fail;
+
+ dbus_message_iter_get_fixed_array(&value, &manuf_data, &len);
+
+ DBG("Adding ManufacturerData for %04x", manuf_id);
+
+ if (!bt_ad_add_manufacturer_data(data, manuf_id, manuf_data,
+ len))
+ goto fail;
+
+ dbus_message_iter_next(&entries);
+ }
+
+ return true;
+
+fail:
+ bt_ad_clear_manufacturer_data(data);
+ return false;
+}
+
+static bool parse_advertising_service_data(GDBusProxy *proxy,
+ struct bt_ad *data)
+{
+ DBusMessageIter iter, entries;
+
+ if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
return false;
+
+ dbus_message_iter_recurse(&iter, &entries);
+
+ bt_ad_clear_service_data(data);
+
+ while (dbus_message_iter_get_arg_type(&entries)
+ == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter value, entry;
+ const char *uuid_str;
+ bt_uuid_t uuid;
+ uint8_t *service_data;
+ int len;
+
+ dbus_message_iter_recurse(&entries, &entry);
+ dbus_message_iter_get_basic(&entry, &uuid_str);
+
+ if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+ goto fail;
+
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
+ goto fail;
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
+ goto fail;
+
+ dbus_message_iter_get_fixed_array(&value, &service_data, &len);
+
+ DBG("Adding ServiceData for %s", uuid_str);
+
+ if (!bt_ad_add_service_data(data, &uuid, service_data, len))
+ goto fail;
+
+ dbus_message_iter_next(&entries);
}
- /* TODO: parse the remaining properties into a shared structure */
+ return true;
- refresh_advertisement(ad);
+fail:
+ bt_ad_clear_service_data(data);
+ return false;
+}
+
+static bool parse_advertising_include_tx_power(GDBusProxy *proxy,
+ bool *included)
+{
+ DBusMessageIter iter;
+ dbus_bool_t b;
+
+ if (!g_dbus_proxy_get_property(proxy, "IncludeTxPower", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+ return false;
+
+ dbus_message_iter_get_basic(&iter, &b);
+
+ *included = b;
return true;
}
-static void advertisement_proxy_added(GDBusProxy *proxy, void *data)
+static void add_adverting_complete(struct advertisement *ad, uint8_t status)
{
- struct advertisement *ad = data;
DBusMessage *reply;
- if (!parse_advertisement(ad)) {
- error("Failed to parse advertisement");
-
+ if (status) {
+ error("Failed to add advertisement: %s (0x%02x)",
+ mgmt_errstr(status), status);
reply = btd_error_failed(ad->reg,
"Failed to register advertisement");
+ queue_remove(ad->manager->ads, ad);
+ g_idle_add(advertisement_free_idle_cb, ad);
+
+ } else
+ reply = dbus_message_new_method_return(ad->reg);
+
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ dbus_message_unref(ad->reg);
+ ad->reg = NULL;
+}
+
+static void add_advertising_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct advertisement *ad = user_data;
+ const struct mgmt_rp_add_advertising *rp = param;
+
+ if (status)
+ goto done;
+
+ if (!param || length < sizeof(*rp)) {
+ status = MGMT_STATUS_FAILED;
goto done;
}
+ ad->instance = rp->instance;
+
g_dbus_client_set_disconnect_watch(ad->client, client_disconnect_cb,
ad);
-
- reply = dbus_message_new_method_return(ad->reg);
-
DBG("Advertisement registered: %s", ad->path);
done:
+ add_adverting_complete(ad, status);
+}
+
+static size_t calc_max_adv_len(struct advertisement *ad, uint32_t flags)
+{
+ size_t max = ad->manager->max_adv_len;
+
+ /*
+ * Flags which reduce the amount of space available for advertising.
+ * See doc/mgmt-api.txt
+ */
+ if (flags & MGMT_ADV_FLAG_TX_POWER)
+ max -= 3;
+
+ if (flags & (MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
+ MGMT_ADV_FLAG_MANAGED_FLAGS))
+ max -= 3;
+
+ if (flags & MGMT_ADV_FLAG_APPEARANCE)
+ max -= 4;
+
+ return max;
+}
+
+static DBusMessage *refresh_advertisement(struct advertisement *ad)
+{
+ struct mgmt_cp_add_advertising *cp;
+ uint8_t param_len;
+ uint8_t *adv_data;
+ size_t adv_data_len;
+ uint32_t flags = 0;
+
+ DBG("Refreshing advertisement: %s", ad->path);
+
+ if (ad->type == AD_TYPE_PERIPHERAL)
+ flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV;
+
+ if (ad->include_tx_power)
+ flags |= MGMT_ADV_FLAG_TX_POWER;
+
+ adv_data = bt_ad_generate(ad->data, &adv_data_len);
+
+ if (!adv_data || (adv_data_len > calc_max_adv_len(ad, flags))) {
+ error("Advertising data too long or couldn't be generated.");
+
+ return g_dbus_create_error(ad->reg, ERROR_INTERFACE
+ ".InvalidLength",
+ "Advertising data too long.");
+ }
+
+ param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len;
+
+ cp = malloc0(param_len);
+
+ if (!cp) {
+ error("Couldn't allocate for MGMT!");
+
+ free(adv_data);
+
+ return btd_error_failed(ad->reg, "Failed");
+ }
+
+ cp->flags = flags;
+ cp->instance = ad->instance;
+ cp->adv_data_len = adv_data_len;
+ memcpy(cp->data, adv_data, adv_data_len);
+
+ free(adv_data);
+
+ if (!mgmt_send(ad->manager->mgmt, MGMT_OP_ADD_ADVERTISING,
+ ad->manager->mgmt_index, param_len, cp,
+ add_advertising_callback, ad, NULL)) {
+ error("Failed to add Advertising Data");
+
+ free(cp);
+
+ return btd_error_failed(ad->reg, "Failed");
+ }
+
+ free(cp);
+
+ return NULL;
+}
+
+static DBusMessage *parse_advertisement(struct advertisement *ad)
+{
+ if (!parse_advertising_type(ad->proxy, &ad->type)) {
+ error("Failed to read \"Type\" property of advertisement");
+ goto fail;
+ }
+
+ if (!parse_advertising_service_uuids(ad->proxy, ad->data)) {
+ error("Property \"ServiceUUIDs\" failed to parse");
+ goto fail;
+ }
+
+ if (!parse_advertising_solicit_uuids(ad->proxy, ad->data)) {
+ error("Property \"SolicitUUIDs\" failed to parse");
+ goto fail;
+ }
+
+ if (!parse_advertising_manufacturer_data(ad->proxy, ad->data)) {
+ error("Property \"ManufacturerData\" failed to parse");
+ goto fail;
+ }
+
+ if (!parse_advertising_service_data(ad->proxy, ad->data)) {
+ error("Property \"ServiceData\" failed to parse");
+ goto fail;
+ }
+
+ if (!parse_advertising_include_tx_power(ad->proxy,
+ &ad->include_tx_power)) {
+ error("Property \"IncludeTxPower\" failed to parse");
+ goto fail;
+ }
+
+ return refresh_advertisement(ad);
+
+fail:
+ return btd_error_failed(ad->reg, "Failed to parse advertisement.");
+}
+
+static void advertisement_proxy_added(GDBusProxy *proxy, void *data)
+{
+ struct advertisement *ad = data;
+ DBusMessage *reply;
+
+ reply = parse_advertisement(ad);
+ if (!reply)
+ return;
+
+ /* Failed to publish for some reason, remove. */
+ queue_remove(ad->manager->ads, ad);
+
+ g_idle_add(advertisement_free_idle_cb, ad);
+
g_dbus_send_message(btd_get_dbus_connection(), reply);
dbus_message_unref(ad->reg);
@@ -219,9 +591,6 @@ static struct advertisement *advertisement_create(DBusConnection *conn,
return NULL;
ad = new0(struct advertisement, 1);
- if (!ad)
- return NULL;
-
ad->client = g_dbus_client_new_full(conn, sender, path, path);
if (!ad->client)
goto fail;
@@ -244,6 +613,10 @@ static struct advertisement *advertisement_create(DBusConnection *conn,
ad->reg = dbus_message_ref(msg);
+ ad->data = bt_ad_new();
+ if (!ad->data)
+ goto fail;
+
return ad;
fail:
@@ -257,8 +630,9 @@ static DBusMessage *register_advertisement(DBusConnection *conn,
{
struct btd_advertising *manager = user_data;
DBusMessageIter args;
- const char *path;
struct advertisement *ad;
+ struct dbus_obj_match match;
+ uint8_t instance;
DBG("RegisterAdvertisement");
@@ -268,28 +642,32 @@ static DBusMessage *register_advertisement(DBusConnection *conn,
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
return btd_error_invalid_args(msg);
- dbus_message_iter_get_basic(&args, &path);
+ dbus_message_iter_get_basic(&args, &match.path);
+
+ match.owner = dbus_message_get_sender(msg);
- if (queue_find(manager->ads, match_advertisement_path, path))
+ if (queue_find(manager->ads, match_advertisement, &match))
return btd_error_already_exists(msg);
- /* TODO: support more than one advertisement */
- if (!queue_isempty(manager->ads))
- return btd_error_failed(msg, "Already advertising");
+ instance = util_get_uid(&manager->instance_bitmap, manager->max_ads);
+ if (!instance)
+ return btd_error_failed(msg, "Maximum advertisements reached");
dbus_message_iter_next(&args);
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
return btd_error_invalid_args(msg);
- ad = advertisement_create(conn, msg, path);
+ ad = advertisement_create(conn, msg, match.path);
if (!ad)
return btd_error_failed(msg,
"Failed to register advertisement");
- DBG("Registered advertisement at path %s", path);
+ DBG("Registered advertisement at path %s", match.path);
+ ad->instance = instance;
ad->manager = manager;
+
queue_push_tail(manager->ads, ad);
return NULL;
@@ -301,8 +679,8 @@ static DBusMessage *unregister_advertisement(DBusConnection *conn,
{
struct btd_advertising *manager = user_data;
DBusMessageIter args;
- const char *path;
struct advertisement *ad;
+ struct dbus_obj_match match;
DBG("UnregisterAdvertisement");
@@ -312,9 +690,11 @@ static DBusMessage *unregister_advertisement(DBusConnection *conn,
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
return btd_error_invalid_args(msg);
- dbus_message_iter_get_basic(&args, &path);
+ dbus_message_iter_get_basic(&args, &match.path);
+
+ match.owner = dbus_message_get_sender(msg);
- ad = queue_find(manager->ads, match_advertisement_path, path);
+ ad = queue_find(manager->ads, match_advertisement, &match);
if (!ad)
return btd_error_does_not_exist(msg);
@@ -341,30 +721,67 @@ static void advertising_manager_destroy(void *user_data)
queue_destroy(manager->ads, advertisement_destroy);
+ mgmt_unref(manager->mgmt);
+
free(manager);
}
+static void read_adv_features_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_advertising *manager = user_data;
+ const struct mgmt_rp_read_adv_features *feat = param;
+
+ if (status || !param) {
+ error("Failed to read advertising features: %s (0x%02x)",
+ mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(*feat)) {
+ error("Wrong size of read adv features response");
+ return;
+ }
+
+ manager->max_adv_len = feat->max_adv_data_len;
+ manager->max_ads = feat->max_instances;
+
+ if (manager->max_ads == 0)
+ return;
+
+ if (!g_dbus_register_interface(btd_get_dbus_connection(),
+ adapter_get_path(manager->adapter),
+ LE_ADVERTISING_MGR_IFACE,
+ methods, NULL, NULL, manager, NULL))
+ error("Failed to register " LE_ADVERTISING_MGR_IFACE);
+}
+
static struct btd_advertising *
advertising_manager_create(struct btd_adapter *adapter)
{
struct btd_advertising *manager;
manager = new0(struct btd_advertising, 1);
- if (!manager)
- return NULL;
-
manager->adapter = adapter;
- if (!g_dbus_register_interface(btd_get_dbus_connection(),
- adapter_get_path(adapter),
- LE_ADVERTISING_MGR_IFACE,
- methods, NULL, NULL, manager,
- advertising_manager_destroy)) {
- error("Failed to register " LE_ADVERTISING_MGR_IFACE);
+ manager->mgmt = mgmt_new_default();
+
+ if (!manager->mgmt) {
+ error("Failed to access management interface");
free(manager);
return NULL;
}
+ manager->mgmt_index = btd_adapter_get_index(adapter);
+
+ if (!mgmt_send(manager->mgmt, MGMT_OP_READ_ADV_FEATURES,
+ manager->mgmt_index, 0, NULL,
+ read_adv_features_callback, manager, NULL)) {
+ error("Failed to read advertising features");
+ advertising_manager_destroy(manager);
+ return NULL;
+ }
+
manager->ads = queue_new();
return manager;
@@ -396,4 +813,6 @@ void btd_advertising_manager_destroy(struct btd_advertising *manager)
g_dbus_unregister_interface(btd_get_dbus_connection(),
adapter_get_path(manager->adapter),
LE_ADVERTISING_MGR_IFACE);
+
+ advertising_manager_destroy(manager);
}
diff --git a/src/agent.c b/src/agent.c
index 12e369ac..ff44d575 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -924,7 +924,7 @@ static void agent_destroy(gpointer data)
static uint8_t parse_io_capability(const char *capability)
{
if (g_str_equal(capability, ""))
- return IO_CAPABILITY_DISPLAYYESNO;
+ return IO_CAPABILITY_KEYBOARDDISPLAY;
if (g_str_equal(capability, "DisplayOnly"))
return IO_CAPABILITY_DISPLAYONLY;
if (g_str_equal(capability, "DisplayYesNo"))
diff --git a/src/attrib-server.c b/src/attrib-server.c
index d334a36b..06293fa6 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -41,6 +41,7 @@
#include "btio/btio.h"
#include "log.h"
+#include "backtrace.h"
#include "adapter.h"
#include "device.h"
#include "src/shared/util.h"
@@ -98,15 +99,6 @@ static bt_uuid_t ccc_uuid = {
.value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
};
-static inline void put_uuid_le(const bt_uuid_t *src, void *dst)
-{
- if (src->type == BT_UUID16)
- put_le16(src->value.u16, dst);
- else
- /* Convert from 128-bit BE to LE */
- bswap_128(&src->value.u128, dst);
-}
-
static void attrib_free(void *data)
{
struct attribute *a = data;
@@ -269,14 +261,7 @@ static int attribute_uuid_cmp(gconstpointer a, gconstpointer b)
const struct attribute *attrib1 = a;
const bt_uuid_t *uuid = b;
- if (attrib1->uuid.value.u16 != GATT_PRIM_SVC_UUID) {
- return bt_uuid_cmp(&attrib1->uuid, uuid);
- } else {
- bt_uuid_t prim_uuid;
- prim_uuid = att_get_uuid(attrib1->data, attrib1->len);
-
- return bt_uuid_cmp(&prim_uuid, uuid);
- }
+ return bt_uuid_cmp(&attrib1->uuid, uuid);
}
struct attribute *attribute_find(struct btd_adapter *adapter, const bt_uuid_t *uuid)
@@ -370,14 +355,20 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
return 0;
if (name != NULL)
+#ifdef __TIZEN_PATCH__
+ sdp_set_info_attr(record, name, "Samsung", NULL);
+#else
sdp_set_info_attr(record, name, "BlueZ", NULL);
+#endif
sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID);
+#ifndef __TIZEN_PATCH__
if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
sdp_set_url_attr(record, "http://www.bluez.org/",
"http://www.bluez.org/",
"http://www.bluez.org/");
}
+#endif
if (adapter_service_add(server->adapter, record) == 0)
return record->handle;
@@ -995,6 +986,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
filename = btd_device_get_storage_path(channel->device, "ccc_sc");
if (!filename) {
warn("Unable to get ccc storage path for device");
+ g_free(data);
return enc_error_resp(ATT_OP_WRITE_REQ, handle,
ATT_ECODE_WRITE_NOT_PERM,
pdu, len);
@@ -1395,12 +1387,12 @@ static gboolean register_core_services(struct gatt_server *server)
atval, 2);
/* GAP service: device name characteristic */
- server->name_handle = 0x0003;
+ server->name_handle = 0x0006;
bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
atval[0] = GATT_CHR_PROP_READ;
put_le16(server->name_handle, &atval[1]);
put_le16(GATT_CHARAC_DEVICE_NAME, &atval[3]);
- attrib_db_add_new(server, 0x0002, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
atval, 5);
/* GAP service: device name attribute */
@@ -1409,12 +1401,12 @@ static gboolean register_core_services(struct gatt_server *server)
ATT_NOT_PERMITTED, NULL, 0);
/* GAP service: device appearance characteristic */
- server->appearance_handle = 0x0005;
+ server->appearance_handle = 0x0008;
bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
atval[0] = GATT_CHR_PROP_READ;
put_le16(server->appearance_handle, &atval[1]);
put_le16(GATT_CHARAC_APPEARANCE, &atval[3]);
- attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
atval, 5);
/* GAP service: device appearance attribute */
@@ -1432,19 +1424,19 @@ static gboolean register_core_services(struct gatt_server *server)
/* GATT service: primary service definition */
bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
put_le16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
- attrib_db_add_new(server, 0x0006, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ attrib_db_add_new(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
atval, 2);
#ifdef __TIZEN_PATCH__
/* GATT service: service changed characteristic */
- service_changed_handle = 0x0008;
+ service_changed_handle = 0x0012;
bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
atval[0] = GATT_CHR_PROP_INDICATE;
put_le16(service_changed_handle, &atval[1]);
put_le16(GATT_CHARAC_SERVICE_CHANGED, &atval[3]);
- attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ attrib_db_add_new(server, 0x0011, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
atval, 5);
/* GATT service: service changed attribute */
@@ -1455,10 +1447,10 @@ static gboolean register_core_services(struct gatt_server *server)
bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
atval[0] = GATT_CHR_PROP_READ | GATT_CHR_PROP_WRITE;
atval[1] = 0;
- attrib_db_add_new(server, 0x0009, &uuid, ATT_NONE, ATT_NONE, atval, 2);
+ attrib_db_add_new(server, 0x0013, &uuid, ATT_NONE, ATT_NONE, atval, 2);
#endif
- server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0006,
+ server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010,
"Generic Attribute Profile");
if (server->gatt_sdp_handle == 0) {
error("Failed to register GATT service record");
@@ -1643,7 +1635,7 @@ static uint16_t find_uuid128_avail(struct btd_adapter *adapter, uint16_t nitems)
uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid,
uint16_t nitems)
{
- g_assert(nitems > 0);
+ btd_assert(nitems > 0);
if (svc_uuid->type == BT_UUID16)
return find_uuid16_avail(adapter, nitems);
@@ -1745,6 +1737,27 @@ int attrib_db_del(struct btd_adapter *adapter, uint16_t handle)
}
#ifdef __TIZEN_PATCH__
+uint16_t send_sc_indication(uint16_t start_handle, uint16_t end_handle, size_t vlen,
+ uint8_t *pdu, size_t len)
+{
+ const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
+
+ if (pdu == NULL)
+ return 0;
+
+ if (len < (vlen + min_len))
+ return 0;
+
+ pdu[0] = ATT_OP_HANDLE_IND;
+/* API replaced by put_le16 in bluez 5.25
+ att_put_u16(start_handle, &pdu[1]);
+ att_put_u16(end_handle, &pdu[3]);*/
+ put_le16(start_handle, &pdu[1]);
+ put_le16(end_handle, &pdu[3]);
+
+ return vlen + min_len;
+}
+
static uint8_t attrib_get_ccc_info(struct btd_device *device, uint16_t handle)
{
uint16_t cccval = 0;
diff --git a/src/backtrace.c b/src/backtrace.c
new file mode 100644
index 00000000..c4387335
--- /dev/null
+++ b/src/backtrace.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <inttypes.h>
+
+#ifdef HAVE_BACKTRACE_SUPPORT
+#include <execinfo.h>
+#include <elfutils/libdwfl.h>
+#endif
+
+#include "src/log.h"
+#include "src/backtrace.h"
+
+void btd_backtrace_init(void)
+{
+#ifdef HAVE_BACKTRACE_SUPPORT
+ void *frames[1];
+
+ /*
+ * initialize the backtracer, since the ctor calls dlopen(), which
+ * calls malloc(), which isn't signal-safe.
+ */
+ backtrace(frames, 1);
+#endif
+}
+
+void btd_backtrace(uint16_t index)
+{
+#ifdef HAVE_BACKTRACE_SUPPORT
+ char *debuginfo_path = NULL;
+ const Dwfl_Callbacks callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .find_elf = dwfl_linux_proc_find_elf,
+ .debuginfo_path = &debuginfo_path,
+ };
+ Dwfl *dwfl;
+ void *frames[48];
+ int n, n_ptrs;
+
+ dwfl = dwfl_begin(&callbacks);
+
+ if (dwfl_linux_proc_report(dwfl, getpid()))
+ goto done;
+
+ dwfl_report_end(dwfl, NULL, NULL);
+
+ n_ptrs = backtrace(frames, 48);
+ if (n_ptrs < 1)
+ goto done;
+
+ btd_error(index, "++++++++ backtrace ++++++++");
+
+ for (n = 1; n < n_ptrs; n++) {
+ GElf_Addr addr = (uintptr_t) frames[n];
+ GElf_Sym sym;
+ GElf_Word shndx;
+ Dwfl_Module *module = dwfl_addrmodule(dwfl, addr);
+ Dwfl_Line *line;
+ const char *name, *modname;
+
+ if (!module) {
+ btd_error(index, "#%-2u ?? [%#" PRIx64 "]", n, addr);
+ continue;
+ }
+
+ name = dwfl_module_addrsym(module, addr, &sym, &shndx);
+ if (!name) {
+ modname = dwfl_module_info(module, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ btd_error(index, "#%-2u ?? (%s) [%#" PRIx64 "]",
+ n, modname, addr);
+ continue;
+ }
+
+ line = dwfl_module_getsrc(module, addr);
+ if (line) {
+ int lineno;
+ const char *src = dwfl_lineinfo(line, NULL, &lineno,
+ NULL, NULL, NULL);
+
+ if (src) {
+ btd_error(index, "#%-2u %s+%#" PRIx64 " "
+ "(%s:%d) [%#" PRIx64 "]",
+ n, name, addr - sym.st_value,
+ src, lineno, addr);
+ continue;
+ }
+ }
+
+ modname = dwfl_module_info(module, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ btd_error(index, "#%-2u %s+%#" PRIx64 " (%s) [%#" PRIx64 "]",
+ n, name, addr - sym.st_value,
+ modname, addr);
+ }
+
+ btd_error(index, "+++++++++++++++++++++++++++");
+
+done:
+ dwfl_end(dwfl);
+#endif
+}
+
+void btd_assertion_message_expr(const char *file, int line,
+ const char *func, const char *expr)
+{
+ btd_error(0xffff, "Assertion failed: (%s) %s:%d in %s",
+ expr, file, line, func);
+ btd_backtrace(0xffff);
+}
diff --git a/src/backtrace.h b/src/backtrace.h
new file mode 100644
index 00000000..b3eef6dd
--- /dev/null
+++ b/src/backtrace.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+void btd_backtrace_init(void);
+void btd_backtrace(uint16_t index);
+
+void btd_assertion_message_expr(const char *file, int line,
+ const char *func, const char *expr);
+
+#define btd_assert(expr) do { \
+ if (expr) ; else \
+ btd_assertion_message_expr(__FILE__, __LINE__, __func__, #expr); \
+ } while (0)
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index bb6b8358..d15003f6 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -35,6 +35,8 @@
<allow send_destination="org.bluez.MediaEndpoint1"/>
<allow own="org.bluez.MediaPlayer1"/>
<allow send_interface="org.bluez.MediaPlayer1"/>
+ <allow send_interface="org.bluez.ThermometerWatcher1"/>
+ <allow send_interface="org.bluez.AlertAgent1"/>
<allow send_destination="org.bluez.MediaPlayer1"/>
<allow own="org.bluez.MediaTransport1"/>
<allow send_interface="org.bluez.MediaTransport1"/>
@@ -113,4 +115,3 @@
</policy>
</busconfig>
-
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 936616bd..adb0a7a4 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -83,8 +83,8 @@ static void append_array_variant(DBusMessageIter *iter, int type, void *val,
dbus_message_iter_close_container(iter, &variant);
}
-void dict_append_entry(DBusMessageIter *dict,
- const char *key, int type, void *val)
+void dict_append_basic(DBusMessageIter *dict, int key_type, const void *key,
+ int type, void *val)
{
DBusMessageIter entry;
@@ -97,28 +97,43 @@ void dict_append_entry(DBusMessageIter *dict,
dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
NULL, &entry);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_append_basic(&entry, key_type, key);
append_variant(&entry, type, val);
dbus_message_iter_close_container(dict, &entry);
+
}
-void dict_append_array(DBusMessageIter *dict, const char *key, int type,
- void *val, int n_elements)
+void dict_append_entry(DBusMessageIter *dict,
+ const char *key, int type, void *val)
+{
+ dict_append_basic(dict, DBUS_TYPE_STRING, &key, type, val);
+}
+
+void dict_append_basic_array(DBusMessageIter *dict, int key_type,
+ const void *key, int type, void *val,
+ int n_elements)
{
DBusMessageIter entry;
dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
NULL, &entry);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_append_basic(&entry, key_type, key);
append_array_variant(&entry, type, val, n_elements);
dbus_message_iter_close_container(dict, &entry);
}
+void dict_append_array(DBusMessageIter *dict, const char *key, int type,
+ void *val, int n_elements)
+{
+ dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
+ n_elements);
+}
+
void set_dbus_connection(DBusConnection *conn)
{
connection = conn;
diff --git a/src/dbus-common.h b/src/dbus-common.h
index f331b2f6..2e7d51e8 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -21,9 +21,14 @@
*
*/
+void dict_append_basic(DBusMessageIter *dict, int key_type, const void *key,
+ int type, void *val);
void dict_append_entry(DBusMessageIter *dict,
const char *key, int type, void *val);
+void dict_append_basic_array(DBusMessageIter *dict, int key_type,
+ const void *key, int type, void *val,
+ int n_elements);
void dict_append_array(DBusMessageIter *dict, const char *key, int type,
void *val, int n_elements);
diff --git a/src/device.c b/src/device.c
index 8ebbcc7e..06f582db 100644
--- a/src/device.c
+++ b/src/device.c
@@ -52,6 +52,7 @@
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-client.h"
#include "src/shared/gatt-server.h"
+#include "src/shared/ad.h"
#include "btio/btio.h"
#include "lib/mgmt.h"
#include "attrib/att.h"
@@ -60,9 +61,6 @@
#include "gatt-database.h"
#include "attrib/gattrib.h"
#include "attio.h"
-#ifdef __TIZEN_PATCH__
-#include "eir.h"
-#endif
#include "device.h"
#include "gatt-client.h"
#include "profile.h"
@@ -76,8 +74,13 @@
#include "textfile.h"
#include "storage.h"
#include "attrib-server.h"
+#include "eir.h"
+
#ifdef __TIZEN_PATCH__
#include "sdp-xml.h"
+#ifdef TIZEN_WEARABLE
+#include <sys/ioctl.h>
+#endif /* TIZEN_WEARABLE */
#endif
#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03
@@ -89,6 +92,13 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
+#define RSSI_THRESHOLD 8
+
+#define GATT_PRIM_SVC_UUID_STR "2800"
+#define GATT_SND_SVC_UUID_STR "2801"
+#define GATT_INCLUDE_UUID_STR "2802"
+#define GATT_CHARAC_UUID_STR "2803"
+
#ifdef __TIZEN_PATCH__
#define DEV_SIMUL_CONTROLLER 0x08 /* Simultaneous LE and BR/EDR to Same
Device Capable (Controller) */
@@ -217,6 +227,12 @@ typedef enum {
DEV_CONNECTED_LE,
DEV_CONNECTED_BREDR_LE,
} dev_connected_state;
+
+struct trusted_profile_t {
+ uint32_t pbap:2;
+ uint32_t map:2;
+ uint32_t sap:2;
+} __packed;
#endif
struct btd_device {
@@ -231,6 +247,7 @@ struct btd_device {
bool svc_refreshed;
GSList *svc_callbacks;
GSList *eir_uuids;
+ struct bt_ad *ad;
char name[MAX_NAME_LENGTH + 1];
char *alias;
uint32_t class;
@@ -246,7 +263,7 @@ struct btd_device {
GSList *services; /* List of btd_service */
GSList *pending; /* Pending services */
GSList *watches; /* List of disconnect_data */
- gboolean temporary;
+ bool temporary;
guint disconn_timer;
guint discov_timer;
struct browse_req *browse; /* service discover request */
@@ -269,6 +286,7 @@ struct btd_device {
* attribute cache support can be built.
*/
struct gatt_db *db; /* GATT db cache */
+ bool gatt_cache_used; /* true if discovery skipped */
struct bt_gatt_client *client; /* GATT client instance */
struct bt_gatt_server *server; /* GATT server instance */
@@ -286,6 +304,9 @@ struct btd_device {
time_t le_seen;
gboolean trusted;
+#ifdef __TIZEN_PATCH__
+ struct trusted_profile_t trusted_profiles;
+#endif
gboolean blocked;
gboolean auto_connect;
gboolean disable_auto_connect;
@@ -293,6 +314,7 @@ struct btd_device {
bool legacy;
int8_t rssi;
+ int8_t tx_power;
GIOChannel *att_io;
guint store_id;
@@ -308,6 +330,7 @@ struct btd_device {
uint16_t auth_payload_timeout;
uint8_t disc_reason;
uint8_t last_bdaddr_type;
+ uint8_t auth_bdaddr_type;
gboolean le_auto_connect;
guint auto_id;
gboolean ipsp_connected; /* IPSP Connection state */
@@ -316,6 +339,12 @@ struct btd_device {
uint16_t max_tx_time;
uint16_t max_rx_octets;
uint16_t max_rx_time;
+ bdaddr_t rpa;
+ bool rpa_exist;
+ bool duplicate;
+ DBusMessage *req_att_mtu; /* Attribute MTU request message */
+ uint8_t irk_val[16];
+ bool pending_conn_update;
#endif
};
@@ -326,6 +355,20 @@ static const uint16_t uuid_list[] = {
0
};
+#ifdef __TIZEN_PATCH__
+typedef enum {
+ SHOW_AUTHORIZATION = 0x0, /* 0b00 */
+ SUPPORTED_BLOCKED = 0x1, /* 0b01 */
+ SUPPORTED_TRUSTED= 0x2, /* 0b10 */
+} bt_profile_trusted_states;
+
+#define PBAP_SHIFT_OFFSET 0
+#define MAP_SHIFT_OFFSET 2
+#define SAP_SHIFT_OFFSET 4
+
+#define PROFILE_SUPPORTED 0x3 /* This corresponds to binary 0b11*/
+#endif
+
static int device_browse_gatt(struct btd_device *device, DBusMessage *msg);
static int device_browse_sdp(struct btd_device *device, DBusMessage *msg);
#ifdef __TIZEN_PATCH__
@@ -333,7 +376,6 @@ static int device_custom_browse_sdp(struct btd_device *device,
DBusMessage *msg, uuid_t *search);
#endif
-
static struct bearer_state *get_state(struct btd_device *dev,
uint8_t bdaddr_type)
{
@@ -477,6 +519,11 @@ static gboolean store_device_info_cb(gpointer user_data)
ba2str(btd_adapter_get_address(device->adapter), adapter_addr);
ba2str(&device->bdaddr, device_addr);
+
+#ifdef __TIZEN_PATCH__
+ if (device->rpa_exist)
+ ba2str(&device->rpa, device_addr);
+#endif
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
device_addr);
@@ -518,7 +565,15 @@ static gboolean store_device_info_cb(gpointer user_data)
g_key_file_set_boolean(key_file, "General", "Trusted",
device->trusted);
-
+#ifdef __TIZEN_PATCH__
+ struct trusted_profile_t trust_profile = device->trusted_profiles;
+ int trusted_profiles = (trust_profile.pbap << PBAP_SHIFT_OFFSET) |
+ (trust_profile.map << MAP_SHIFT_OFFSET) |
+ (trust_profile.sap << SAP_SHIFT_OFFSET);
+ DBG("Storing TrustedProfiles %d", trusted_profiles);
+ g_key_file_set_integer(key_file, "General", "TrustedProfiles",
+ trusted_profiles);
+#endif
g_key_file_set_boolean(key_file, "General", "Blocked",
device->blocked);
@@ -559,6 +614,17 @@ static gboolean store_device_info_cb(gpointer user_data)
g_key_file_remove_key(key_file, "General",
"ManufacturerDataLen", NULL);
}
+
+ if (device->rpa_exist) {
+ char irk_addr[18];
+
+ ba2str(&device->bdaddr, irk_addr);
+ g_key_file_set_string(key_file, "General", "IdentityAddress",
+ irk_addr);
+ } else {
+ g_key_file_remove_key(key_file, "General", "IdentityAddress",
+ NULL);
+ }
#endif
if (device->vendor_src) {
@@ -636,6 +702,12 @@ void device_store_cached_name(struct btd_device *dev, const char *name)
ba2str(btd_adapter_get_address(dev->adapter), s_addr);
ba2str(&dev->bdaddr, d_addr);
+
+#ifdef __TIZEN_PATCH__
+ if (dev->rpa_exist)
+ ba2str(&dev->rpa, d_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", s_addr, d_addr);
create_file(filename, S_IRUSR | S_IWUSR);
@@ -652,6 +724,9 @@ void device_store_cached_name(struct btd_device *dev, const char *name)
static void browse_request_free(struct browse_req *req)
{
+#ifdef __TIZEN_PATCH__
+ DBG("");
+#endif
if (req->listener_id)
g_dbus_remove_watch(dbus_conn, req->listener_id);
if (req->msg)
@@ -673,13 +748,6 @@ static void gatt_client_cleanup(struct btd_device *device)
bt_gatt_client_unref(device->client);
device->client = NULL;
- /*
- * TODO: Once GATT over BR/EDR is properly supported, we should check
- * the bonding state for the correct bearer based on the transport over
- * which GATT is being done.
- */
- if (!device->le_state.bonded)
- gatt_db_clear(device->db);
}
static void gatt_server_cleanup(struct btd_device *device)
@@ -767,10 +835,15 @@ static void device_free(gpointer user_data)
g_slist_free_full(device->attios_offline, g_free);
g_slist_free_full(device->svc_callbacks, svc_dev_remove);
+ /* Reset callbacks since the device is going to be freed */
+ gatt_db_register(device->db, NULL, NULL, NULL, NULL);
+
attio_cleanup(device);
gatt_db_unref(device->db);
+ bt_ad_unref(device->ad);
+
if (device->tmp_records)
sdp_list_free(device->tmp_records,
(sdp_free_func_t) sdp_record_free);
@@ -863,6 +936,42 @@ gboolean device_is_trusted(struct btd_device *device)
return device->trusted;
}
+#ifdef __TIZEN_PATCH__
+gboolean device_is_profile_trusted(struct btd_device *device,
+ const char *uuid)
+{
+ DBG("UUID %s", uuid);
+ if (g_strcmp0(uuid, OBEX_PSE_UUID) == 0) {
+ if (device->trusted_profiles.pbap == SUPPORTED_TRUSTED)
+ return true;
+ } else if (g_strcmp0(uuid, OBEX_MAS_UUID) == 0) {
+ if (device->trusted_profiles.map == SUPPORTED_TRUSTED)
+ return true;
+ } else if (g_strcmp0(uuid, SAP_UUID) == 0) {
+ if (device->trusted_profiles.sap == SUPPORTED_TRUSTED)
+ return true;
+ }
+ return false;
+}
+
+gboolean device_is_profile_blocked(struct btd_device *device,
+ const char *uuid)
+{
+ DBG("UUID %s", uuid);
+ if (g_strcmp0(uuid, OBEX_PSE_UUID) == 0) {
+ if (device->trusted_profiles.pbap == SUPPORTED_BLOCKED)
+ return true;
+ } else if (g_strcmp0(uuid, OBEX_MAS_UUID) == 0) {
+ if (device->trusted_profiles.map == SUPPORTED_BLOCKED)
+ return true;
+ } else if (g_strcmp0(uuid, SAP_UUID) == 0) {
+ if (device->trusted_profiles.sap == SUPPORTED_BLOCKED)
+ return true;
+ }
+ return false;
+}
+#endif
+
static gboolean dev_property_get_address(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1057,13 +1166,6 @@ static gboolean dev_property_get_paired(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
struct btd_device *dev = data;
-
-#if 0 /* Need to discuss with SLP team */
-/* #ifdef __TIZEN_PATCH__ */
- uint8_t val = device_get_paired_state(dev);
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &val);
-#else
dbus_bool_t val;
if (dev->bredr_state.paired || dev->le_state.paired)
@@ -1072,7 +1174,6 @@ static gboolean dev_property_get_paired(const GDBusPropertyTable *property,
val = FALSE;
dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
-#endif
return TRUE;
}
@@ -1110,6 +1211,64 @@ static gboolean dev_property_exists_rssi(const GDBusPropertyTable *property,
return TRUE;
}
+static gboolean dev_property_get_tx_power(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *dev = data;
+ dbus_int16_t val = dev->tx_power;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &val);
+
+ return TRUE;
+}
+
+static gboolean dev_property_exists_tx_power(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct btd_device *dev = data;
+
+ if (dev->tx_power == 127)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void append_service_path(const char *path, void *user_data)
+{
+ DBusMessageIter *array = user_data;
+
+ dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static gboolean dev_property_get_gatt_services(
+ const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *dev = data;
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
+
+ btd_gatt_client_foreach_service(dev->client_dbus, append_service_path,
+ &array);
+
+ dbus_message_iter_close_container(iter, &array);
+
+ return TRUE;
+}
+
+static gboolean dev_property_exists_gatt_services(
+ const GDBusPropertyTable *property,
+ void *data)
+{
+ struct btd_device *dev = data;
+
+ if (!dev->client || !bt_gatt_client_is_ready(dev->client))
+ return FALSE;
+
+ return TRUE;
+}
+
static gboolean dev_property_get_trusted(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1148,6 +1307,26 @@ static void dev_property_set_trusted(const GDBusPropertyTable *property,
set_trust(id, b, data);
}
+#ifdef __TIZEN_PATCH__
+static gboolean dev_property_get_trusted_profiles(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *device = data;
+ uint32_t pbap = device->trusted_profiles.pbap;
+ uint32_t map = device->trusted_profiles.map;
+ uint32_t sap = device->trusted_profiles.sap;
+
+ unsigned int val = (pbap << PBAP_SHIFT_OFFSET) |
+ (map << MAP_SHIFT_OFFSET) |
+ (sap << SAP_SHIFT_OFFSET);
+
+ DBG("TrustedProfiles : %d", val);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &val);
+
+ return TRUE;
+}
+#endif
+
static gboolean dev_property_get_blocked(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1256,6 +1435,17 @@ static gboolean dev_property_get_ipsp_conn_state(const GDBusPropertyTable *prope
return TRUE;
}
+
+static gboolean dev_property_get_att_mtu(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *device = data;
+ dbus_uint16_t mtu = bt_gatt_client_get_mtu(device->client);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &mtu);
+
+ return TRUE;
+}
#endif
static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
@@ -1360,7 +1550,6 @@ static gboolean dev_property_get_adapter(const GDBusPropertyTable *property,
}
#ifdef __TIZEN_PATCH__
-
static gboolean property_get_flag(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
{
@@ -1413,6 +1602,87 @@ gboolean device_get_gatt_connected(const struct btd_device *device)
}
#endif
+static void append_manufacturer_data(void *data, void *user_data)
+{
+ struct bt_ad_manufacturer_data *md = data;
+ DBusMessageIter *dict = user_data;
+
+ dict_append_basic_array(dict, DBUS_TYPE_UINT16, &md->manufacturer_id,
+ DBUS_TYPE_BYTE, &md->data, md->len);
+}
+
+static gboolean
+dev_property_get_manufacturer_data(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *device = data;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_UINT16_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &dict);
+
+ bt_ad_foreach_manufacturer_data(device->ad, append_manufacturer_data,
+ &dict);
+
+ dbus_message_iter_close_container(iter, &dict);
+
+ return TRUE;
+}
+
+static gboolean
+dev_property_manufacturer_data_exist(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct btd_device *device = data;
+
+ return bt_ad_has_manufacturer_data(device->ad, NULL);
+}
+
+static void append_service_data(void *data, void *user_data)
+{
+ struct bt_ad_service_data *sd = data;
+ DBusMessageIter *dict = user_data;
+ char uuid_str[MAX_LEN_UUID_STR];
+
+ bt_uuid_to_string(&sd->uuid, uuid_str, sizeof(uuid_str));
+
+ dict_append_array(dict, uuid_str, DBUS_TYPE_BYTE, &sd->data, sd->len);
+}
+
+static gboolean
+dev_property_get_service_data(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *device = data;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &dict);
+
+ bt_ad_foreach_service_data(device->ad, append_service_data, &dict);
+
+ dbus_message_iter_close_container(iter, &dict);
+
+ return TRUE;
+}
+
+static gboolean
+dev_property_service_data_exist(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct btd_device *device = data;
+
+ return bt_ad_has_service_data(device->ad, NULL);
+}
+
static gboolean disconnect_all(gpointer user_data)
{
struct btd_device *device = user_data;
@@ -1537,6 +1807,12 @@ void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
if (device->browse)
browse_request_cancel(device->browse);
+ if (device->att_io) {
+ g_io_channel_shutdown(device->att_io, FALSE, NULL);
+ g_io_channel_unref(device->att_io);
+ device->att_io = NULL;
+ }
+
if (device->connect) {
DBusMessage *reply = btd_error_failed(device->connect,
"Cancelled");
@@ -1584,6 +1860,11 @@ void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
device);
}
+bool device_is_disconnecting(struct btd_device *device)
+{
+ return device->disconn_timer > 0;
+}
+
static void device_set_auto_connect(struct btd_device *device, gboolean enable)
{
char addr[18];
@@ -1645,7 +1926,8 @@ static int connect_next(struct btd_device *dev)
while (dev->pending) {
service = dev->pending->data;
- if (btd_service_connect(service) == 0)
+ err = btd_service_connect(service);
+ if (!err)
return 0;
dev->pending = g_slist_delete_link(dev->pending, dev->pending);
@@ -1665,8 +1947,10 @@ static void device_profile_connected(struct btd_device *dev,
if (!err)
btd_device_set_temporary(dev, false);
+#ifndef __TIZEN_PATCH__
if (dev->pending == NULL)
- return;
+ goto done;
+#endif
if (!btd_device_is_connected(dev)) {
switch (-err) {
@@ -1677,6 +1961,10 @@ static void device_profile_connected(struct btd_device *dev,
}
}
+#ifdef __TIZEN_PATCH__
+ if (dev->pending == NULL)
+ return;
+#endif
pending = dev->pending->data;
l = find_service_with_profile(dev->pending, profile);
@@ -1751,6 +2039,45 @@ void device_add_eir_uuids(struct btd_device *dev, GSList *uuids)
DEVICE_INTERFACE, "UUIDs");
}
+static void add_manufacturer_data(void *data, void *user_data)
+{
+ struct eir_msd *msd = data;
+ struct btd_device *dev = user_data;
+
+ if (!bt_ad_add_manufacturer_data(dev->ad, msd->company, msd->data,
+ msd->data_len))
+ return;
+
+ g_dbus_emit_property_changed(dbus_conn, dev->path,
+ DEVICE_INTERFACE, "ManufacturerData");
+}
+
+void device_set_manufacturer_data(struct btd_device *dev, GSList *list)
+{
+ g_slist_foreach(list, add_manufacturer_data, dev);
+}
+
+static void add_service_data(void *data, void *user_data)
+{
+ struct eir_sd *sd = data;
+ struct btd_device *dev = user_data;
+ bt_uuid_t uuid;
+
+ if (bt_string_to_uuid(&uuid, sd->uuid) < 0)
+ return;
+
+ if (!bt_ad_add_service_data(dev->ad, &uuid, sd->data, sd->data_len))
+ return;
+
+ g_dbus_emit_property_changed(dbus_conn, dev->path,
+ DEVICE_INTERFACE, "ServiceData");
+}
+
+void device_set_service_data(struct btd_device *dev, GSList *list)
+{
+ g_slist_foreach(list, add_service_data, dev);
+}
+
static struct btd_service *find_connectable_service(struct btd_device *dev,
const char *uuid)
{
@@ -1879,8 +2206,7 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services)
for (l = services; l; l = g_slist_next(l)) {
struct btd_service *service = l->data;
- dev->pending = g_slist_append(dev->pending,
- btd_service_ref(service));
+ dev->pending = g_slist_append(dev->pending, service);
}
return connect_next(dev);
@@ -1925,8 +2251,11 @@ static DBusMessage *connect_profiles(struct btd_device *dev, uint8_t bdaddr_type
}
err = connect_next(dev);
- if (err < 0)
+ if (err < 0) {
+ if (err == -EALREADY)
+ return dbus_message_new_method_return(msg);
return btd_error_failed(msg, strerror(-err));
+ }
dev->connect = dbus_message_ref(msg);
@@ -2128,6 +2457,11 @@ static void store_services(struct btd_device *device)
ba2str(btd_adapter_get_address(adapter), src_addr);
ba2str(&device->bdaddr, dst_addr);
+#ifdef __TIZEN_PATCH__
+ if (device->rpa_exist)
+ ba2str(&device->rpa, dst_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
dst_addr);
key_file = g_key_file_new();
@@ -2175,6 +2509,153 @@ static void store_services(struct btd_device *device)
g_key_file_free(key_file);
}
+struct gatt_saver {
+ struct btd_device *device;
+ GKeyFile *key_file;
+};
+
+static void store_desc(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct gatt_saver *saver = user_data;
+ GKeyFile *key_file = saver->key_file;
+ char handle[6], value[100], uuid_str[MAX_LEN_UUID_STR];
+ const bt_uuid_t *uuid;
+ uint16_t handle_num;
+
+ handle_num = gatt_db_attribute_get_handle(attr);
+ sprintf(handle, "%04hx", handle_num);
+
+ uuid = gatt_db_attribute_get_type(attr);
+ bt_uuid_to_string(uuid, uuid_str, sizeof(uuid_str));
+ sprintf(value, "%s", uuid_str);
+ g_key_file_set_string(key_file, "Attributes", handle, value);
+}
+
+static void store_chrc(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct gatt_saver *saver = user_data;
+ GKeyFile *key_file = saver->key_file;
+ char handle[6], value[100], uuid_str[MAX_LEN_UUID_STR];
+ uint16_t handle_num, value_handle;
+ uint8_t properties;
+ bt_uuid_t uuid;
+
+ if (!gatt_db_attribute_get_char_data(attr, &handle_num, &value_handle,
+ &properties, &uuid)) {
+ warn("Error storing characteristic - can't get data");
+ return;
+ }
+
+ sprintf(handle, "%04hx", handle_num);
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+ sprintf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hhx:%s", value_handle,
+ properties, uuid_str);
+ g_key_file_set_string(key_file, "Attributes", handle, value);
+
+ gatt_db_service_foreach_desc(attr, store_desc, saver);
+}
+
+static void store_incl(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct gatt_saver *saver = user_data;
+ GKeyFile *key_file = saver->key_file;
+ struct gatt_db_attribute *service;
+ char handle[6], value[100], uuid_str[MAX_LEN_UUID_STR];
+ uint16_t handle_num, start, end;
+ bt_uuid_t uuid;
+
+ if (!gatt_db_attribute_get_incl_data(attr, &handle_num, &start, &end)) {
+ warn("Error storing included service - can't get data");
+ return;
+ }
+
+ service = gatt_db_get_attribute(saver->device->db, start);
+ if (!service) {
+ warn("Error storing included service - can't find it");
+ return;
+ }
+
+ sprintf(handle, "%04hx", handle_num);
+
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+ sprintf(value, GATT_INCLUDE_UUID_STR ":%04hx:%04hx:%s", start,
+ end, uuid_str);
+
+ g_key_file_set_string(key_file, "Attributes", handle, value);
+}
+
+static void store_service(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct gatt_saver *saver = user_data;
+ GKeyFile *key_file = saver->key_file;
+ char uuid_str[MAX_LEN_UUID_STR], handle[6], value[256];
+ uint16_t start, end;
+ bt_uuid_t uuid;
+ bool primary;
+ char *type;
+
+ if (!gatt_db_attribute_get_service_data(attr, &start, &end, &primary,
+ &uuid)) {
+ warn("Error storing service - can't get data");
+ return;
+ }
+
+ sprintf(handle, "%04hx", start);
+
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+
+ if (primary)
+ type = GATT_PRIM_SVC_UUID_STR;
+ else
+ type = GATT_SND_SVC_UUID_STR;
+
+ sprintf(value, "%s:%04hx:%s", type, end, uuid_str);
+
+ g_key_file_set_string(key_file, "Attributes", handle, value);
+
+ gatt_db_service_foreach_incl(attr, store_incl, saver);
+ gatt_db_service_foreach_char(attr, store_chrc, saver);
+}
+
+static void store_gatt_db(struct btd_device *device)
+{
+ struct btd_adapter *adapter = device->adapter;
+ char filename[PATH_MAX];
+ char src_addr[18], dst_addr[18];
+ GKeyFile *key_file;
+ char *data;
+ gsize length = 0;
+ struct gatt_saver saver;
+
+ if (device_address_is_private(device)) {
+ warn("Can't store GATT db for private addressed device %s",
+ device->path);
+ return;
+ }
+
+ ba2str(btd_adapter_get_address(adapter), src_addr);
+ ba2str(&device->bdaddr, dst_addr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr,
+ dst_addr);
+ create_file(filename, S_IRUSR | S_IWUSR);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ saver.key_file = key_file;
+ saver.device = device;
+
+ gatt_db_foreach_service(device->db, NULL, store_service, &saver);
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(filename, data, length, NULL);
+
+ g_free(data);
+ g_key_file_free(key_file);
+}
+
+
static void browse_request_complete(struct browse_req *req, uint8_t bdaddr_type,
int err)
{
@@ -2227,9 +2708,18 @@ static void device_svc_resolved(struct btd_device *dev, uint8_t bdaddr_type,
struct bearer_state *state = get_state(dev, bdaddr_type);
struct browse_req *req = dev->browse;
+#ifdef __TIZEN_PATCH__
+ DBG("%s bdaddr_type %d err %d", dev->path, bdaddr_type, err);
+#else
DBG("%s err %d", dev->path, err);
+#endif
+#ifndef __TIZEN_PATCH__
state->svc_resolved = true;
+#else
+ if (err == 0)
+ state->svc_resolved = true;
+#endif
/* Disconnection notification can happen before this function
* gets called, so don't set svc_refreshed for a disconnected
@@ -2269,6 +2759,14 @@ static void device_svc_resolved(struct btd_device *dev, uint8_t bdaddr_type,
if (!req)
return;
+#ifdef __TIZEN_PATCH__
+ /* If bdaddr_type is LE but req is for SDP, don't complete browse req. */
+ if (bdaddr_type != BDADDR_BREDR && req->search_uuid) {
+ DBG("Discover comp. is for LE but browse req. is for SDP.");
+ return;
+ }
+#endif
+
dev->browse = NULL;
browse_request_complete(req, bdaddr_type, err);
}
@@ -2508,7 +3006,9 @@ static DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
"Authentication Rejected");
case MGMT_STATUS_CANCELLED:
case MGMT_STATUS_NO_RESOURCES:
+#ifndef __TIZEN_PATCH__
case MGMT_STATUS_DISCONNECTED:
+#endif
return dbus_message_new_error(msg,
ERROR_INTERFACE ".AuthenticationCanceled",
"Authentication Canceled");
@@ -2658,22 +3158,9 @@ static DBusMessage *discover_services(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);
- if (strlen(pattern) == 0) {
- err = device_custom_browse_sdp(device, msg, NULL);
- if (err < 0)
- goto fail;
- } else {
- uuid_t uuid;
-
- if (bt_string2uuid(&uuid, pattern) < 0)
- return btd_error_invalid_args(msg);
-
- sdp_uuid128_to_uuid(&uuid);
-
- err = device_custom_browse_sdp(device, msg, &uuid);
- if (err < 0)
- goto fail;
- }
+ err = device_browse_sdp(device, msg);
+ if (err < 0)
+ goto fail;
return NULL;
@@ -2850,11 +3337,13 @@ void device_set_gatt_connected(struct btd_device *device, gboolean connected)
return;
}
- if (device->gatt_connected != connected)
- device->gatt_connected = connected;
-
+ if (device->gatt_connected == connected) {
+ error("same state change for gatt_connected : %d", connected);
+ return;
+ }
DBG("GattConnected %d", connected);
+ device->gatt_connected = connected;
g_dbus_emit_property_changed(dbus_conn, device->path,
DEVICE_INTERFACE, "GattConnected");
}
@@ -2878,19 +3367,13 @@ static DBusMessage *connect_le(DBusConnection *conn, DBusMessage *msg,
DBG("bdaddr_type %d", device->bdaddr_type);
- /*
- * Current bt_adapter_start_device_discovery() cannot scan BREDR and LE
- * simultaneously. And bdaddr_type is not supporting both BREDR and LE
- * type. So, device for LE is created when connect_le() called.
- */
- if (device->bdaddr_type == BDADDR_BREDR) {
- if(device->le)
- device->bdaddr_type = BDADDR_LE_PUBLIC;
- else {
- device = btd_adapter_get_device(device->adapter,
- &device->bdaddr, BDADDR_LE_PUBLIC);
- if (device == NULL)
- return btd_error_no_such_adapter(msg);
+ if (!device->le) {
+ DBG("device->le is not set. Find or create device object");
+ device = btd_adapter_get_device(device->adapter,
+ &device->bdaddr, BDADDR_LE_PUBLIC);
+ if (device == NULL) {
+ error("Cannot create device object");
+ return btd_error_not_supported(msg);
}
}
@@ -2924,15 +3407,10 @@ static DBusMessage *connect_le(DBusConnection *conn, DBusMessage *msg,
adapter_add_le_white_list(device->adapter, device);
}
- if (device->att_io == NULL)
- device->attio_id = btd_device_add_attio_callback(device,
- NULL, NULL, device);
-
if (device->auto_id == 0)
device->auto_id = g_timeout_add(200, att_connect, device);
- device->connect = dbus_message_ref(msg);
- return NULL;
+ return dbus_message_new_method_return(msg);
}
static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
@@ -2940,7 +3418,7 @@ static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
{
struct btd_device *device = user_data;
- if (device->bdaddr_type == BDADDR_BREDR)
+ if (!device->le)
return btd_error_not_supported(msg);
if (device->le_auto_connect && !device->le_state.connected) {
@@ -2960,31 +3438,13 @@ static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
if (!device->le_state.connected)
return btd_error_not_connected(msg);
- if (device->connect) {
- DBusMessage *reply = btd_error_failed(device->connect,
- "Cancelled");
- g_dbus_send_message(dbus_conn, reply);
- dbus_message_unref(device->connect);
- device->connect = NULL;
- }
-
- if (device->le_state.connected)
- device->disconnects = g_slist_append(device->disconnects,
- dbus_message_ref(msg));
-
- disconnect_all(device);
-
- /*
- * Current bt_adapter_start_device_discovery() cannot scan BREDR and LE
- * simultaneously. And bdaddr_type is not supporting both BREDR and LE
- * type. So, bdaddr_type is returned to bredr after disconnect le.
- */
- if(device->bredr)
- device->bdaddr_type = BDADDR_BREDR;
+ btd_adapter_disconnect_device(device->adapter, &device->bdaddr,
+ device->bdaddr_type);
- return NULL;
+ return dbus_message_new_method_return(msg);
}
+#ifdef __TIZEN_PATCH__
static DBusMessage *connect_ipsp(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
@@ -3074,14 +3534,58 @@ static DBusMessage *le_set_data_length(
return dbus_message_new_method_return(msg);
}
+static DBusMessage *set_trusted_profile(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_device *dev = data;
+ dbus_bool_t profile_trusted;
+ const char *pattern;
+ char *uuid;
+ uint32_t value;
+ uint32_t pbap = dev->trusted_profiles.pbap;
+ uint32_t map = dev->trusted_profiles.map;
+ uint32_t sap = dev->trusted_profiles.sap;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_BOOLEAN, &profile_trusted,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ DBG("Pattern : %s", pattern);
+ uuid = bt_name2string(pattern);
+ DBG("UUID : %s", uuid);
+ DBG("profile Trusted : %d %d %d", dev->trusted_profiles.pbap,
+ dev->trusted_profiles.map, dev->trusted_profiles.sap);
+ if (g_strcmp0(uuid, OBEX_PBAP_UUID) == 0) {
+ if (profile_trusted)
+ pbap = SUPPORTED_TRUSTED;
+ else
+ pbap = SUPPORTED_BLOCKED;
+ } else if (g_strcmp0(uuid, OBEX_MAP_UUID) == 0) {
+ if (profile_trusted)
+ map = SUPPORTED_TRUSTED;
+ else
+ map = SUPPORTED_BLOCKED;
+ } else if (g_strcmp0(uuid, SAP_UUID) == 0) {
+ if (profile_trusted)
+ sap = SUPPORTED_TRUSTED;
+ else
+ sap = SUPPORTED_BLOCKED;
+ } else {
+ return btd_error_invalid_args(msg);
+ }
+
+ btd_device_set_trusted_profiles(dev, pbap, map, sap);
+ return dbus_message_new_method_return(msg);
+}
+#endif
+
static DBusMessage *is_connected_profile(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
struct btd_device *dev = user_data;
struct btd_service *service;
-#ifndef __TIZEN_PATCH__
- struct btd_profile *profile;
-#endif
btd_service_state_t state;
const char *pattern;
char *uuid;
@@ -3099,16 +3603,16 @@ static DBusMessage *is_connected_profile(DBusConnection *conn, DBusMessage *msg,
uuid = bt_name2string(pattern);
DBG("is_connected_profile_uuid : %s", uuid);
service = btd_device_get_service(dev, uuid);
-#ifdef __TIZEN_PATCH__
+
if ((service == NULL) && (g_strcmp0(uuid, HFP_HS_UUID) == 0)) {
DBG("HFP service is not found check for HSP service");
service = btd_device_get_service(dev, HSP_HS_UUID);
}
if (uuid)
free(uuid);
-#endif
+
if (!service)
- return btd_error_not_supported(msg);
+ return btd_error_not_connected(msg);
state = btd_service_get_state(service);
DBG("Connected State : %d", state);
@@ -3156,6 +3660,199 @@ static DBusMessage *le_conn_update(DBusConnection *conn, DBusMessage *msg,
else
return dbus_message_new_method_return(msg);
}
+
+static DBusMessage *update_le_conn_parm(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_device *device = user_data;
+ GIOChannel *io;
+ int fd;
+ struct le_conn_param param = {0, 0, 0, 0};
+
+ DBG("");
+
+ if (device == NULL) {
+ error("device is NULL");
+ return btd_error_invalid_args(msg);
+ }
+
+ if (!device->le) {
+ error("le is not supported");
+ return btd_error_not_supported(msg);
+ }
+
+ if (!device->gatt_connected || !device->attrib)
+ return btd_error_not_connected(msg);
+
+ io = g_attrib_get_channel(device->attrib);
+ if (!io)
+ return btd_error_not_connected(msg);
+
+ fd = g_io_channel_unix_get_fd(io);
+ if (fd < 0)
+ return btd_error_not_connected(msg);
+
+#ifdef __TIZEN_PATCH__
+ if (device_get_conn_update_state(device))
+ return btd_error_in_progress(msg);
+ else
+ device_set_conn_update_state(device, true);
+#endif
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &param.min,
+ DBUS_TYPE_UINT32, &param.max,
+ DBUS_TYPE_UINT32, &param.latency,
+ DBUS_TYPE_UINT32, &param.to_multiplier,
+ DBUS_TYPE_INVALID)) {
+ error("Invalid args");
+ return btd_error_invalid_args(msg);
+ }
+
+ if (setsockopt(fd, SOL_BLUETOOTH, BT_LE_CONN_PARAM,
+ &param, sizeof(param)) < 0) {
+ error("Can't Update LE conn param : %s (%d)",
+ strerror(errno), errno);
+ return btd_error_failed(msg, strerror(errno));
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static void device_request_att_mtu_reponse_cb(bool success, uint8_t att_ecode,
+ void *user_data)
+{
+ struct btd_device *device = user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ uint16_t mtu;
+
+ if (!device->req_att_mtu)
+ return;
+
+ mtu = bt_gatt_client_get_mtu(device->client);
+
+ if (!success) {
+ const char *err_if;
+ err_if = ERROR_INTERFACE ".Failed";
+
+ reply = dbus_message_new_error(device->req_att_mtu, err_if,
+ "Request Att MTU failed");
+ g_dbus_send_message(dbus_conn, reply);
+ return;
+ }
+
+ DBG("MTU exchange complete, with MTU: %u", mtu);
+
+ reply = dbus_message_new_method_return(device->req_att_mtu);
+ if (!reply)
+ return;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+ &mtu);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE,
+ &att_ecode);
+ g_dbus_send_message(dbus_conn, reply);
+
+ dbus_message_unref(device->req_att_mtu);
+ device->req_att_mtu = NULL;
+}
+
+static DBusMessage *request_att_mtu(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_device *device = user_data;
+ uint16_t mtu;
+
+ DBG("");
+
+ if (device == NULL) {
+ error("device is NULL");
+ return btd_error_invalid_args(msg);
+ }
+
+ if (!device->le) {
+ error("le is not supported");
+ return btd_error_not_supported(msg);
+ }
+
+ if (!device->gatt_connected || !device->attrib)
+ return btd_error_not_connected(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT16, &mtu,
+ DBUS_TYPE_INVALID)) {
+ error("Invalid args");
+ return btd_error_invalid_args(msg);
+ }
+
+ DBG("MTU %d", mtu);
+
+ if (!bt_gatt_request_att_mtu(device->client, mtu,
+ device_request_att_mtu_reponse_cb, device))
+ return btd_error_failed(msg, "Unable to Request MTU");
+
+ device->req_att_mtu = dbus_message_ref(msg);
+ return NULL;
+}
+
+static DBusMessage *device_get_ida(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_device *device = user_data;
+ char device_idaddr[18] = { 0 };
+ DBusMessage *reply;
+ const gchar *id_address;
+
+ DBG("");
+
+ if (device == NULL) {
+ error("device is NULL");
+ return btd_error_invalid_args(msg);
+ }
+
+ if (!device->le) {
+ error("le is not supported");
+ return btd_error_not_supported(msg);
+ }
+
+ DBG("bdaddr_type %d", device->bdaddr_type);
+
+ /* Device will have its IDA only if device has RPA */
+ if (device->rpa_exist) {
+ DBG("device->rpa_exist");
+ ba2str(&device->bdaddr, device_idaddr);
+ }
+ else {
+ DBG("device->rpa_exist does not exist");
+ return btd_error_does_not_exist(msg);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ id_address = g_strdup(device_idaddr);
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &id_address,
+ DBUS_TYPE_INVALID);
+ return reply;
+}
+
+void device_set_conn_update_state(struct btd_device *device, bool state)
+{
+ if (!device)
+ return;
+
+ device->pending_conn_update = state;
+}
+
+bool device_get_conn_update_state(struct btd_device *device)
+{
+ return device->pending_conn_update;
+}
#endif
static const GDBusMethodTable device_methods[] = {
@@ -3187,17 +3884,17 @@ static const GDBusMethodTable device_methods[] = {
{ GDBUS_METHOD("ReadPayloadTimeout", NULL,
NULL, read_auth_payload_timeout)},
#endif
- { GDBUS_ASYNC_METHOD("ConnectLE",
+ { GDBUS_METHOD("ConnectLE",
GDBUS_ARGS({ "auto_connect", "b"}),
NULL, connect_le) },
- { GDBUS_ASYNC_METHOD("DisconnectLE", NULL, NULL, disconnect_le) },
+ { GDBUS_METHOD("DisconnectLE", NULL, NULL, disconnect_le) },
{ GDBUS_METHOD("IsConnectedProfile", GDBUS_ARGS({ "UUID", "s" }),
GDBUS_ARGS({ "IsConnected", "b" }), is_connected_profile)},
{ GDBUS_METHOD("LeConnUpdate",
GDBUS_ARGS({ "interval_min", "u" },
{ "interval_max", "u" }, { "latency", "u" },
{ "time_out", "u" }), NULL,
- le_conn_update) },
+ update_le_conn_parm) },
{ GDBUS_ASYNC_METHOD("DiscoverServices",
GDBUS_ARGS({ "pattern", "s" }), NULL,
discover_services) },
@@ -3208,6 +3905,16 @@ static const GDBusMethodTable device_methods[] = {
GDBUS_ARGS({"max_tx_octets", "q" },
{ "max_tx_time", "q" }), NULL,
le_set_data_length)},
+ { GDBUS_ASYNC_METHOD("RequestAttMtu",
+ GDBUS_ARGS({ "mtu", "q" }),
+ GDBUS_ARGS({ "mtu", "q" }, { "status", "y"}),
+ request_att_mtu) },
+ { GDBUS_METHOD("GetIDAddress", NULL,
+ GDBUS_ARGS({ "IDAdress", "s" }),
+ device_get_ida) },
+ { GDBUS_METHOD("SetTrustedProfile",
+ GDBUS_ARGS({ "uuid", "s"}, { "trusted", "b"}),
+ NULL, set_trusted_profile) },
#endif
{ }
};
@@ -3222,12 +3929,7 @@ static const GDBusPropertyTable device_properties[] = {
dev_property_exists_appearance },
{ "Icon", "s", dev_property_get_icon, NULL,
dev_property_exists_icon },
-#if 0 /* Need to discuss with SLP team */
-/* #ifdef __TIZEN_PATCH__ */
- { "Paired", "y", dev_property_get_paired },
-#else
{ "Paired", "b", dev_property_get_paired },
-#endif
{ "Trusted", "b", dev_property_get_trusted, dev_property_set_trusted },
{ "Blocked", "b", dev_property_get_blocked, dev_property_set_blocked },
{ "LegacyPairing", "b", dev_property_get_legacy },
@@ -3251,14 +3953,29 @@ static const GDBusPropertyTable device_properties[] = {
{ "PayloadTimeout", "q", dev_property_get_payload},
{ "LastAddrType", "y", dev_property_get_last_addr_type},
{ "IpspConnected", "b", dev_property_get_ipsp_conn_state },
+ { "AttMtu", "q", dev_property_get_att_mtu },
+ { "TrustedProfiles", "u", dev_property_get_trusted_profiles},
#endif
+ { "ManufacturerData", "a{qv}", dev_property_get_manufacturer_data,
+ NULL, dev_property_manufacturer_data_exist,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "ServiceData", "a{sv}", dev_property_get_service_data,
+ NULL, dev_property_service_data_exist,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "TxPower", "n", dev_property_get_tx_power, NULL,
+ dev_property_exists_tx_power,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "GattServices", "ao", dev_property_get_gatt_services, NULL,
+ dev_property_exists_gatt_services,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+
{ }
};
#ifdef __TIZEN_PATCH__
static const GDBusSignalTable device_signals[] = {
{ GDBUS_SIGNAL("Disconnected",
- GDBUS_ARGS({ "bdaddr_type", "y" }, { "reason", "y" })) },
+ GDBUS_ARGS({ "bdaddr_type", "y" }, { "reason", "y" }, { "name", "s" })) },
{ GDBUS_SIGNAL("DeviceConnected",
GDBUS_ARGS({ "bdaddr_type", "y"})) },
{ GDBUS_SIGNAL("ProfileStateChanged",
@@ -3316,6 +4033,18 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type)
g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE,
"Connected");
#else
+#ifdef TIZEN_WEARABLE
+ if (bdaddr_type == BDADDR_BREDR &&
+ get_charging_state(dev->adapter) == WIRELESS_CHARGING) {
+ int br_pkt_type = ACL_PTYPE_MASK |
+ HCI_2DH1 | HCI_2DH3 | HCI_2DH5 |
+ HCI_3DH1 | HCI_3DH3 | HCI_3DH5;
+
+ DBG("During wireless charging... Change packet type");
+ device_change_pkt_type(dev, (gpointer)br_pkt_type);
+ }
+#endif /* TIZEN_WEARABLE */
+
g_dbus_emit_signal(dbus_conn, dev->path,
DEVICE_INTERFACE, "DeviceConnected",
DBUS_TYPE_BYTE, &bdaddr_type,
@@ -3326,6 +4055,9 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type)
void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type)
{
struct bearer_state *state = get_state(device, bdaddr_type);
+#ifdef __TIZEN_PATCH__
+ char *dev_name = device->name;
+#endif
if (!state->connected)
return;
@@ -3369,6 +4101,7 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type)
DEVICE_INTERFACE, "Disconnected",
DBUS_TYPE_BYTE, &bdaddr_type,
DBUS_TYPE_BYTE, &device->disc_reason,
+ DBUS_TYPE_STRING, &dev_name,
DBUS_TYPE_INVALID);
#endif
}
@@ -3538,6 +4271,16 @@ static void load_info(struct btd_device *device, const char *local,
g_free(str);
}
}
+
+ str = g_key_file_get_string(key_file, "General", "IdentityAddress",
+ NULL);
+
+ /* Folder name is RPA(Resolvable Private Address), So we need to swap it */
+ if (str) {
+ memcpy(&device->rpa, &device->bdaddr, sizeof(bdaddr_t));
+ str2ba(str, &device->bdaddr);
+ device->rpa_exist = true;
+ }
#endif
/* Load device technology */
@@ -3581,6 +4324,19 @@ next:
device->trusted = g_key_file_get_boolean(key_file, "General",
"Trusted", NULL);
+#ifdef __TIZEN_PATCH__
+ /* Load Trusted Profiles*/
+ int trusted_profiles = g_key_file_get_integer(key_file, "General",
+ "TrustedProfiles", NULL);
+ DBG("Loading TrustedProfiles %d", trusted_profiles);
+ device->trusted_profiles.pbap = ((trusted_profiles &
+ (PROFILE_SUPPORTED << PBAP_SHIFT_OFFSET)) >> PBAP_SHIFT_OFFSET);
+ device->trusted_profiles.map = ((trusted_profiles &
+ (PROFILE_SUPPORTED << MAP_SHIFT_OFFSET)) >> MAP_SHIFT_OFFSET);
+ device->trusted_profiles.sap = ((trusted_profiles &
+ (PROFILE_SUPPORTED << SAP_SHIFT_OFFSET)) >> SAP_SHIFT_OFFSET);
+#endif
+
/* Load device blocked */
blocked = g_key_file_get_boolean(key_file, "General", "Blocked", NULL);
if (blocked)
@@ -3743,6 +4499,256 @@ static void add_primary(struct gatt_db_attribute *attr, void *user_data)
*new_services = g_slist_append(*new_services, prim);
}
+static int load_desc(char *handle, char *value,
+ struct gatt_db_attribute *service)
+{
+ char uuid_str[MAX_LEN_UUID_STR];
+ struct gatt_db_attribute *att;
+ uint16_t handle_int;
+ bt_uuid_t uuid;
+
+ if (sscanf(handle, "%04hx", &handle_int) != 1)
+ return -EIO;
+
+ if (sscanf(value, "%s", uuid_str) != 1)
+ return -EIO;
+
+ bt_string_to_uuid(&uuid, uuid_str);
+
+ DBG("loading descriptor handle: 0x%04x, uuid: %s", handle_int,
+ uuid_str);
+
+ att = gatt_db_service_insert_descriptor(service, handle_int, &uuid,
+ 0, NULL, NULL, NULL);
+ if (!att || gatt_db_attribute_get_handle(att) != handle_int) {
+ warn("loading descriptor to db failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int load_chrc(char *handle, char *value,
+ struct gatt_db_attribute *service)
+{
+ uint16_t properties, value_handle, handle_int;
+ char uuid_str[MAX_LEN_UUID_STR];
+ struct gatt_db_attribute *att;
+ bt_uuid_t uuid;
+
+ if (sscanf(handle, "%04hx", &handle_int) != 1)
+ return -EIO;
+
+ if (sscanf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hx:%s", &value_handle,
+ &properties, uuid_str) != 3)
+ return -EIO;
+
+ bt_string_to_uuid(&uuid, uuid_str);
+
+ /* Log debug message. */
+ DBG("loading characteristic handle: 0x%04x, value handle: 0x%04x,"
+ " properties 0x%04x uuid: %s", handle_int,
+ value_handle, properties, uuid_str);
+
+ att = gatt_db_service_insert_characteristic(service, value_handle,
+ &uuid, 0, properties,
+ NULL, NULL, NULL);
+ if (!att || gatt_db_attribute_get_handle(att) != value_handle) {
+ warn("saving characteristic to db failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int load_incl(struct gatt_db *db, char *handle, char *value,
+ struct gatt_db_attribute *service)
+{
+ char uuid_str[MAX_LEN_UUID_STR];
+ struct gatt_db_attribute *att;
+ uint16_t start, end;
+
+ if (sscanf(handle, "%04hx", &start) != 1)
+ return -EIO;
+
+ if (sscanf(value, GATT_INCLUDE_UUID_STR ":%04hx:%04hx:%s", &start, &end,
+ uuid_str) != 3)
+ return -EIO;
+
+ /* Log debug message. */
+ DBG("loading included service: 0x%04x, end: 0x%04x, uuid: %s", start,
+ end, uuid_str);
+
+ att = gatt_db_get_attribute(db, start);
+ if (!att) {
+ warn("saving included service to db failed - no such service");
+ return -EIO;
+ }
+
+ att = gatt_db_service_add_included(service, att);
+ if (!att) {
+ warn("saving included service to db failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int load_service(struct gatt_db *db, char *handle, char *value)
+{
+ struct gatt_db_attribute *att;
+ uint16_t start, end;
+ char type[MAX_LEN_UUID_STR], uuid_str[MAX_LEN_UUID_STR];
+ bt_uuid_t uuid;
+ bool primary;
+
+ if (sscanf(handle, "%04hx", &start) != 1)
+ return -EIO;
+
+ if (sscanf(value, "%[^:]:%04hx:%s", type, &end, uuid_str) != 3)
+ return -EIO;
+
+ if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR))
+ primary = true;
+ else if (g_str_equal(type, GATT_SND_SVC_UUID_STR))
+ primary = false;
+ else
+ return -EIO;
+
+ bt_string_to_uuid(&uuid, uuid_str);
+
+ /* Log debug message. */
+ DBG("loading service: 0x%04x, end: 0x%04x, uuid: %s",
+ start, end, uuid_str);
+
+ att = gatt_db_insert_service(db, start, &uuid, primary,
+ end - start + 1);
+ if (!att) {
+ DBG("ERROR saving service to db!");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int load_gatt_db_impl(GKeyFile *key_file, char **keys,
+ struct gatt_db *db)
+{
+ struct gatt_db_attribute *current_service;
+ char **handle, *value, type[MAX_LEN_UUID_STR];
+ int ret;
+
+ /* first load service definitions */
+ for (handle = keys; *handle; handle++) {
+ value = g_key_file_get_string(key_file, "Attributes", *handle,
+ NULL);
+
+ if (sscanf(value, "%[^:]:", type) != 1) {
+ warn("Missing Type in attribute definition");
+ g_free(value);
+ return -EIO;
+ }
+
+ if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR) ||
+ g_str_equal(type, GATT_SND_SVC_UUID_STR)) {
+ ret = load_service(db, *handle, value);
+ if (ret) {
+ g_free(value);
+ return ret;
+ }
+ }
+
+ g_free(value);
+ }
+
+ current_service = NULL;
+ /* then fill them with data*/
+ for (handle = keys; *handle; handle++) {
+ value = g_key_file_get_string(key_file, "Attributes", *handle,
+ NULL);
+
+ if (sscanf(value, "%[^:]:", type) != 1) {
+ warn("Missing Type in attribute definition");
+ g_free(value);
+ return -EIO;
+ }
+
+ if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR) ||
+ g_str_equal(type, GATT_SND_SVC_UUID_STR)) {
+ uint16_t tmp;
+ uint16_t start, end;
+ bool primary;
+ bt_uuid_t uuid;
+ char uuid_str[MAX_LEN_UUID_STR];
+
+ if (sscanf(*handle, "%04hx", &tmp) != 1) {
+ warn("Unable to parse attribute handle");
+ g_free(value);
+ return -EIO;
+ }
+
+ if (current_service)
+ gatt_db_service_set_active(current_service,
+ true);
+
+ current_service = gatt_db_get_attribute(db, tmp);
+
+ gatt_db_attribute_get_service_data(current_service,
+ &start, &end,
+ &primary, &uuid);
+
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+ } else if (g_str_equal(type, GATT_INCLUDE_UUID_STR)) {
+ ret = load_incl(db, *handle, value, current_service);
+ } else if (g_str_equal(type, GATT_CHARAC_UUID_STR)) {
+ ret = load_chrc(*handle, value, current_service);
+ } else {
+ ret = load_desc(*handle, value, current_service);
+ }
+
+ g_free(value);
+ if (ret)
+ return ret;
+ }
+
+ if (current_service)
+ gatt_db_service_set_active(current_service, true);
+
+ return 0;
+}
+
+static void load_gatt_db(struct btd_device *device, const char *local,
+ const char *peer)
+{
+ char **keys, filename[PATH_MAX];
+ GKeyFile *key_file;
+
+ DBG("Restoring %s gatt database from file", peer);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+ keys = g_key_file_get_keys(key_file, "Attributes", NULL, NULL);
+
+ if (!keys) {
+ warn("No cache for %s", peer);
+ g_key_file_free(key_file);
+ return;
+ }
+
+ if (load_gatt_db_impl(key_file, keys, device->db))
+ warn("Unable to load gatt db from file for %s", peer);
+
+ g_strfreev(keys);
+ g_key_file_free(key_file);
+
+ g_slist_free_full(device->primaries, g_free);
+ device->primaries = NULL;
+ gatt_db_foreach_service(device->db, NULL, add_primary,
+ &device->primaries);
+}
+
static void device_add_uuids(struct btd_device *device, GSList *uuids)
{
GSList *l;
@@ -3765,14 +4771,6 @@ static void device_add_uuids(struct btd_device *device, GSList *uuids)
DEVICE_INTERFACE, "UUIDs");
}
-struct gatt_probe_data {
- struct btd_device *dev;
- bool all_services;
- GSList *uuids;
- struct gatt_db_attribute *cur_attr;
- char cur_uuid[MAX_LEN_UUID_STR];
-};
-
static bool device_match_profile(struct btd_device *device,
struct btd_profile *profile,
GSList *uuids)
@@ -3787,84 +4785,50 @@ static bool device_match_profile(struct btd_device *device,
return true;
}
-static void dev_probe_gatt(struct btd_profile *p, void *user_data)
+static void add_gatt_service(struct gatt_db_attribute *attr, void *user_data)
{
- struct gatt_probe_data *data = user_data;
+ struct btd_device *device = user_data;
struct btd_service *service;
-
- if (p->device_probe == NULL)
- return;
-
- if (!p->remote_uuid || bt_uuid_strcmp(p->remote_uuid, data->cur_uuid))
- return;
-
- service = service_create(data->dev, p);
- if (!service)
- return;
-
- if (service_probe(service) < 0) {
- btd_service_unref(service);
- return;
- }
-
- /* Mark service as claimed */
- gatt_db_service_set_claimed(data->cur_attr, true);
-
- data->dev->services = g_slist_append(data->dev->services, service);
-}
-
-static void dev_probe_gatt_profile(struct gatt_db_attribute *attr,
- void *user_data)
-{
- struct gatt_probe_data *data = user_data;
+ struct btd_profile *profile;
bt_uuid_t uuid;
- GSList *l = NULL;
+ char uuid_str[MAX_LEN_UUID_STR];
+ GSList *l;
gatt_db_attribute_get_service_uuid(attr, &uuid);
- bt_uuid_to_string(&uuid, data->cur_uuid, sizeof(data->cur_uuid));
-
- data->cur_attr = attr;
-
- /*
- * If we're probing for all services, store the UUID since device->uuids
- * was cleared.
- */
- if (data->all_services)
- data->uuids = g_slist_append(data->uuids,
- g_strdup(data->cur_uuid));
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
- /* Don't probe the profiles if a matching service already exists. */
- if (find_service_with_uuid(data->dev->services, data->cur_uuid)) {
- /* Mark the service as claimed by the existing profile. */
- gatt_db_service_set_claimed(data->cur_attr, true);
- return;
- }
+ /* Check if service was already probed */
+ l = find_service_with_uuid(device->services, uuid_str);
+ if (l)
+ goto done;
- btd_profile_foreach(dev_probe_gatt, data);
+ /* Add UUID and probe service */
+ btd_device_add_uuid(device, uuid_str);
- if (data->all_services)
+ /* Check if service was probed */
+ l = find_service_with_uuid(device->services, uuid_str);
+ if (!l)
return;
- l = g_slist_append(l, g_strdup(data->cur_uuid));
- device_add_uuids(data->dev, l);
-}
-
-static void device_probe_gatt_profile(struct btd_device *device,
- struct gatt_db_attribute *attr)
-{
- struct gatt_probe_data data;
+done:
+ /* Mark service as active to skip discovering it again */
+ gatt_db_service_set_active(attr, true);
- memset(&data, 0, sizeof(data));
+ service = l->data;
+ profile = btd_service_get_profile(service);
- data.dev = device;
+ /* Claim attributes of internal profiles */
+ if (!profile->external) {
+ /* Mark the service as claimed by the existing profile. */
+ gatt_db_service_set_claimed(attr, true);
+ }
- dev_probe_gatt_profile(attr, &data);
- g_slist_free_full(data.uuids, g_free);
+ /* Notify driver about the new connection */
+ service_accept(service);
}
-static void device_probe_gatt_profiles(struct btd_device *device)
+static void device_add_gatt_services(struct btd_device *device)
{
- struct gatt_probe_data data;
char addr[18];
ba2str(&device->bdaddr, addr);
@@ -3874,27 +4838,41 @@ static void device_probe_gatt_profiles(struct btd_device *device)
return;
}
- memset(&data, 0, sizeof(data));
+ gatt_db_foreach_service(device->db, NULL, add_gatt_service, device);
+}
- data.dev = device;
- data.all_services = true;
+#ifdef __TIZEN_PATCH__
+static void accept_gatt_service(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct btd_device *device = user_data;
+ GSList *l;
+ bt_uuid_t uuid;
+ char uuid_str[MAX_LEN_UUID_STR];
- gatt_db_foreach_service(device->db, NULL, dev_probe_gatt_profile,
- &data);
+ gatt_db_attribute_get_service_uuid(attr, &uuid);
+ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+
+ l = find_service_with_uuid(device->services, uuid_str);
+ if (!l)
+ return;
- device_add_uuids(device, data.uuids);
- g_slist_free_full(data.uuids, g_free);
+ service_accept(l->data);
}
+#endif
static void device_accept_gatt_profiles(struct btd_device *device)
{
GSList *l;
+#ifdef __TIZEN_PATCH__
+ gatt_db_foreach_service(device->db, NULL, accept_gatt_service, device);
+#else
for (l = device->services; l != NULL; l = g_slist_next(l))
service_accept(l->data);
+#endif
}
-static void device_remove_gatt_profile(struct btd_device *device,
+static void device_remove_gatt_service(struct btd_device *device,
struct gatt_db_attribute *attr)
{
struct btd_service *service;
@@ -3915,20 +4893,28 @@ static void device_remove_gatt_profile(struct btd_device *device,
service_remove(service);
}
+static gboolean gatt_services_changed(gpointer user_data)
+{
+ struct btd_device *device = user_data;
+
+ store_gatt_db(device);
+
+ g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE,
+ "GattServices");
+
+ return FALSE;
+}
+
static void gatt_service_added(struct gatt_db_attribute *attr, void *user_data)
{
struct btd_device *device = user_data;
GSList *new_service = NULL;
- bt_uuid_t uuid;
- char uuid_str[MAX_LEN_UUID_STR];
uint16_t start, end;
- GSList *l;
if (!bt_gatt_client_is_ready(device->client))
return;
- gatt_db_attribute_get_service_data(attr, &start, &end, NULL, &uuid);
- bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+ gatt_db_attribute_get_service_data(attr, &start, &end, NULL, NULL);
DBG("start: 0x%04x, end: 0x%04x", start, end);
@@ -3940,25 +4926,13 @@ static void gatt_service_added(struct gatt_db_attribute *attr, void *user_data)
if (!new_service)
return;
- l = find_service_with_uuid(device->services, uuid_str);
-
device_register_primaries(device, new_service, -1);
- /*
- * If the profile was probed for the first time then call accept on
- * the service.
- */
- if (!l) {
- l = find_service_with_uuid(device->services, uuid_str);
- if (l)
- service_accept(l->data);
- }
-
- device_probe_gatt_profile(device, attr);
-
- store_device_info(device);
+ add_gatt_service(attr, device);
btd_gatt_client_service_added(device->client_dbus, attr);
+
+ gatt_services_changed(device);
}
static gint prim_attr_cmp(gconstpointer a, gconstpointer b)
@@ -4033,7 +5007,7 @@ static void gatt_service_removed(struct gatt_db_attribute *attr,
* remove it anyway.
*/
if (device->client || device->temporary == TRUE)
- device_remove_gatt_profile(device, attr);
+ device_remove_gatt_service(device, attr);
g_free(l->data);
device->uuids = g_slist_delete_link(device->uuids, l);
@@ -4046,6 +5020,8 @@ static void gatt_service_removed(struct gatt_db_attribute *attr,
store_device_info(device);
btd_gatt_client_service_removed(device->client_dbus, attr);
+
+ gatt_services_changed(device);
}
static struct btd_device *device_new(struct btd_adapter *adapter,
@@ -4061,12 +5037,20 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
if (device == NULL)
return NULL;
+ device->tx_power = 127;
+
device->db = gatt_db_new();
if (!device->db) {
g_free(device);
return NULL;
}
+ device->ad = bt_ad_new();
+ if (!device->ad) {
+ device_free(device);
+ return NULL;
+ }
+
address_up = g_ascii_strup(address, -1);
device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up);
g_strdelimit(device->path, ":", '_');
@@ -4150,6 +5134,11 @@ struct btd_device *device_create(struct btd_adapter *adapter,
else
device->le = true;
+#ifdef __TIZEN_PATCH__
+ if (bdaddr_type == BDADDR_LE_RANDOM)
+ bacpy(&device->rpa, bdaddr);
+#endif
+
sba = btd_adapter_get_address(adapter);
ba2str(sba, src);
@@ -4176,6 +5165,11 @@ char *btd_device_get_storage_path(struct btd_device *device,
ba2str(btd_adapter_get_address(device->adapter), srcaddr);
ba2str(&device->bdaddr, dstaddr);
+#ifdef __TIZEN_PATCH__
+ if (device->rpa_exist)
+ ba2str(&device->rpa, dstaddr);
+#endif
+
if (!filename)
return g_strdup_printf(STORAGEDIR "/%s/%s", srcaddr, dstaddr);
@@ -4264,6 +5258,24 @@ void device_set_bredr_support(struct btd_device *device)
store_device_info(device);
}
+#ifdef __TIZEN_PATCH__
+void device_set_rpa(struct btd_device *device, const bdaddr_t *rpa)
+{
+ DBG("rpa exist: %d", device->rpa_exist);
+
+ if (device->rpa_exist == false) {
+ /* Only use first RPA value even if the device was re-paired */
+ bacpy(&device->rpa, rpa);
+ device->rpa_exist = true;
+ }
+}
+
+void device_set_irk_value(struct btd_device *device, const char *val)
+{
+ memcpy(&device->irk_val, val, sizeof(device->irk_val));
+}
+#endif
+
void device_set_le_support(struct btd_device *device, uint8_t bdaddr_type)
{
if (device->le)
@@ -4316,6 +5328,15 @@ void device_merge_duplicate(struct btd_device *dev, struct btd_device *dup)
dev->vendor = dup->vendor;
dev->product = dup->product;
dev->version = dup->version;
+
+#ifdef __TIZEN_PATCH__
+ for (l = dup->services; l; l = g_slist_next(l)) {
+ struct btd_service *svc = l->data;
+ dev->services = g_slist_append(dev->services, btd_service_ref(svc));
+ }
+
+ dup->duplicate = true;
+#endif
}
uint32_t btd_device_get_class(struct btd_device *device)
@@ -4404,6 +5425,11 @@ static void device_remove_stored(struct btd_device *device)
ba2str(src, adapter_addr);
ba2str(&device->bdaddr, device_addr);
+#ifdef __TIZEN_PATCH__
+ if (device->rpa_exist)
+ ba2str(&device->rpa, device_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", adapter_addr,
device_addr);
delete_folder_tree(filename);
@@ -4470,10 +5496,23 @@ void device_unpair(struct btd_device *device, gboolean remove_stored)
if (remove_stored)
device_remove_stored(device);
+ gatt_db_clear(device->db);
+
+ if (device->rpa_exist) {
+ bacpy(&device->bdaddr, &device->rpa);
+ device->bdaddr_type = BDADDR_LE_RANDOM;
+
+ bacpy(&device->rpa, BDADDR_ANY);
+ device->rpa_exist = false;
+ }
+
device->bredr_state.paired = 0;
device->le_state.paired = 0;
device->bredr_state.svc_resolved = false;
device->trusted = false;
+ device->trusted_profiles.pbap = SHOW_AUTHORIZATION;
+ device->trusted_profiles.map = SHOW_AUTHORIZATION;
+ device->trusted_profiles.sap = SHOW_AUTHORIZATION;
if (device->alias != NULL) {
/* Remove alias name because
* In UG if we rename and then unpair device and
@@ -4490,6 +5529,22 @@ void device_unpair(struct btd_device *device, gboolean remove_stored)
// btd_device_unref(device);
DBG("-");
}
+
+void device_remove_stored_folder(struct btd_device *device)
+{
+ const bdaddr_t *src = btd_adapter_get_address(device->adapter);
+ char adapter_addr[18];
+ char device_addr[18];
+ char filename[PATH_MAX];
+
+ ba2str(src, adapter_addr);
+ ba2str(&device->bdaddr, device_addr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", adapter_addr,
+ device_addr);
+
+ delete_folder_tree(filename);
+}
#endif
void device_remove(struct btd_device *device, gboolean remove_stored)
@@ -4537,6 +5592,29 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
btd_device_unref(device);
}
+#ifdef __TIZEN_PATCH__
+int device_rpa_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct btd_device *device = a;
+ const char *address = b;
+ char addr[18];
+
+ ba2str(&device->rpa, addr);
+ return strcasecmp(addr, address);
+}
+
+int device_addr_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct btd_device *device = a;
+ const bdaddr_t *bdaddr = b;
+
+ if (device->duplicate)
+ return -1;
+
+ return bacmp(&device->bdaddr, bdaddr);
+}
+#endif
+
int device_address_cmp(gconstpointer a, gconstpointer b)
{
const struct btd_device *device = a;
@@ -4596,6 +5674,66 @@ int device_addr_type_cmp(gconstpointer a, gconstpointer b)
return cmp;
}
+#ifdef TIZEN_WEARABLE
+void device_change_pkt_type(gpointer data, gpointer user_data)
+{
+ uint16_t pkt_type = (uint16_t)user_data;
+ struct btd_device *device = data;
+ struct hci_conn_info_req *cr;
+ set_conn_ptype_cp cp;
+ char addr[18];
+ int hdev = 0;
+ int err = 0;
+
+ /* Change a packet type only for Phone device */
+ if ((device->class & 0x00001F00) >> 8 != 0x02)
+ return;
+
+ if (!device->bredr_state.connected)
+ return;
+
+ hdev = hci_open_dev(0);
+ if (hdev < 0) {
+ error("Cannot open hdev");
+ return;
+ }
+
+ cr = g_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (cr == NULL) {
+ error("Out of memory");
+ return;
+ }
+ cr->type = ACL_LINK;
+ bacpy(&cr->bdaddr, &device->bdaddr);
+
+ err = ioctl(hdev, HCIGETCONNINFO, cr);
+ if (err < 0) {
+ error("Fail to get HCIGETCOINFO");
+ g_free(cr);
+ hci_close_dev(hdev);
+ return;
+ }
+
+ cp.handle = cr->conn_info->handle;
+ g_free(cr);
+ cp.pkt_type = cpu_to_le16(pkt_type);
+
+ ba2str(&device->bdaddr, addr);
+ DBG("Handle %d, Addr %s", cp.handle, addr);
+ DBG("Send Change pkt type request : 0x%X", pkt_type);
+
+ if (hci_send_cmd(hdev, OGF_LINK_CTL, OCF_SET_CONN_PTYPE,
+ SET_CONN_PTYPE_CP_SIZE, &cp) < 0) {
+ error("hci_send_cmd is failed");
+ hci_close_dev(hdev);
+ return;
+ }
+
+ hci_close_dev(hdev);
+ return;
+}
+#endif /* TIZEN_WEARABLE */
+
static gboolean record_has_uuid(const sdp_record_t *rec,
const char *profile_uuid)
{
@@ -4630,45 +5768,54 @@ struct probe_data {
GSList *uuids;
};
-static void dev_probe(struct btd_profile *p, void *user_data)
+static struct btd_service *probe_service(struct btd_device *device,
+ struct btd_profile *profile,
+ GSList *uuids)
{
- struct probe_data *d = user_data;
struct btd_service *service;
- if (p->device_probe == NULL)
- return;
+ if (profile->device_probe == NULL)
+ return NULL;
- if (!device_match_profile(d->dev, p, d->uuids))
- return;
+ if (!device_match_profile(device, profile, uuids))
+ return NULL;
- service = service_create(d->dev, p);
+ service = service_create(device, profile);
- if (service_probe(service) < 0) {
+ if (service_probe(service)) {
btd_service_unref(service);
- return;
+ return NULL;
}
- d->dev->services = g_slist_append(d->dev->services, service);
+#ifndef __TIZEN_PATCH__
+ if (profile->auto_connect)
+ device_set_auto_connect(device, TRUE);
+#endif
+
+ return service;
}
-void device_probe_profile(gpointer a, gpointer b)
+static void dev_probe(struct btd_profile *p, void *user_data)
{
- struct btd_device *device = a;
- struct btd_profile *profile = b;
+ struct probe_data *d = user_data;
struct btd_service *service;
- if (profile->device_probe == NULL)
+ service = probe_service(d->dev, p, d->uuids);
+ if (!service)
return;
- if (!device_match_profile(device, profile, device->uuids))
- return;
+ d->dev->services = g_slist_append(d->dev->services, service);
+}
- service = service_create(device, profile);
+void device_probe_profile(gpointer a, gpointer b)
+{
+ struct btd_device *device = a;
+ struct btd_profile *profile = b;
+ struct btd_service *service;
- if (service_probe(service) < 0) {
- btd_service_unref(service);
+ service = probe_service(device, profile, device->uuids);
+ if (!service)
return;
- }
device->services = g_slist_append(device->services, service);
@@ -4831,27 +5978,30 @@ static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
char srcaddr[18], dstaddr[18];
char sdp_file[PATH_MAX];
char att_file[PATH_MAX];
- GKeyFile *sdp_key_file = NULL;
- GKeyFile *att_key_file = NULL;
+ GKeyFile *sdp_key_file;
+ GKeyFile *att_key_file;
char *data;
gsize length = 0;
ba2str(btd_adapter_get_address(device->adapter), srcaddr);
ba2str(&device->bdaddr, dstaddr);
- if (!device->temporary) {
- snprintf(sdp_file, PATH_MAX, STORAGEDIR "/%s/cache/%s",
- srcaddr, dstaddr);
+#ifdef __TIZEN_PATCH__
+ if (device->rpa_exist)
+ ba2str(&device->rpa, dstaddr);
+#endif
- sdp_key_file = g_key_file_new();
- g_key_file_load_from_file(sdp_key_file, sdp_file, 0, NULL);
+ snprintf(sdp_file, PATH_MAX, STORAGEDIR "/%s/cache/%s", srcaddr,
+ dstaddr);
- snprintf(att_file, PATH_MAX, STORAGEDIR "/%s/%s/attributes",
- srcaddr, dstaddr);
+ sdp_key_file = g_key_file_new();
+ g_key_file_load_from_file(sdp_key_file, sdp_file, 0, NULL);
- att_key_file = g_key_file_new();
- g_key_file_load_from_file(att_key_file, att_file, 0, NULL);
- }
+ snprintf(att_file, PATH_MAX, STORAGEDIR "/%s/%s/attributes", srcaddr,
+ dstaddr);
+
+ att_key_file = g_key_file_new();
+ g_key_file_load_from_file(att_key_file, att_file, 0, NULL);
for (seq = recs; seq; seq = seq->next) {
sdp_record_t *rec = (sdp_record_t *) seq->data;
@@ -5178,15 +6328,24 @@ static void register_gatt_services(struct btd_device *device)
btd_device_set_temporary(device, false);
+#ifdef __TIZEN_PATCH__
+ if (req) {
+ if (req->search_uuid)
+ DBG("browse req. is for SDP. Ignore it.");
+ else
+ update_gatt_uuids(req, device->primaries, services);
+ }
+#else
if (req)
update_gatt_uuids(req, device->primaries, services);
+#endif
g_slist_free_full(device->primaries, g_free);
device->primaries = NULL;
device_register_primaries(device, services, -1);
- device_probe_gatt_profiles(device);
+ device_add_gatt_services(device);
device_svc_resolved(device, device->bdaddr_type, 0);
}
@@ -5198,6 +6357,8 @@ static void gatt_client_debug_func(const char *str, void *user_data)
}
#endif
+static void gatt_client_init(struct btd_device *device);
+
static void gatt_client_ready_cb(bool success, uint8_t att_ecode,
void *user_data)
{
@@ -5206,33 +6367,35 @@ static void gatt_client_ready_cb(bool success, uint8_t att_ecode,
DBG("status: %s, error: %u", success ? "success" : "failed", att_ecode);
if (!success) {
- if (device->browse) {
- struct browse_req *req = device->browse;
-
- device->browse = NULL;
- browse_request_complete(req, device->bdaddr_type, -EIO);
- }
-
-#ifdef __TIZEN_PATCH__
- if (device->attachid == 0) {
- error("GATT client / server both are not connected");
- return;
- }
-
- error("Even though GATT client's connection is failed, "
- "because GATT server's connection is made, "
- "update GATT connection state.");
- device_set_gatt_connected(device, TRUE);
-#endif
-
+ device_svc_resolved(device, device->bdaddr_type, -EIO);
return;
}
register_gatt_services(device);
- device_accept_gatt_profiles(device);
-
btd_gatt_client_ready(device->client_dbus);
+
+ /*
+ * Update the GattServices property. Do this asynchronously since this
+ * should happen after the "Characteristics" and "Descriptors"
+ * properties of all services have been asynchronously updated by
+ * btd_gatt_client.
+ *
+ * Service discovery will be skipped and exported objects won't change
+ * if the attribute cache was populated when bt_gatt_client gets
+ * initialized, so no need to to send this signal if that's the case.
+ */
+ if (!device->gatt_cache_used)
+ g_idle_add(gatt_services_changed, device);
+
+#ifdef __TIZEN_PATCH__
+ if (device->name[0] == '\0') {
+ char *name = NULL;
+ name = bt_gatt_client_get_gap_device_name(device->client);
+ if (name)
+ strncpy(device->name, name, MAX_NAME_LENGTH);
+ }
+#endif
}
static void gatt_client_service_changed(uint16_t start_handle,
@@ -5270,6 +6433,12 @@ static void gatt_client_init(struct btd_device *device)
/* Notify attio so it can react to notifications */
g_slist_foreach(device->attios, attio_connected, device->attrib);
+ /*
+ * Notify notify existing service about the new connection so they can
+ * react to notifications while discovering services
+ */
+ device_accept_gatt_profiles(device);
+
if (!bt_gatt_client_set_ready_handler(device->client,
gatt_client_ready_cb,
device, NULL)) {
@@ -5285,6 +6454,10 @@ static void gatt_client_init(struct btd_device *device)
gatt_client_cleanup(device);
return;
}
+
+ device->gatt_cache_used = !gatt_db_isempty(device->db);
+
+ btd_gatt_client_connected(device->client_dbus);
}
static void gatt_server_init(struct btd_device *device, struct gatt_db *db)
@@ -5339,6 +6512,8 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
uint16_t mtu;
uint16_t cid;
struct btd_gatt_database *database;
+ const bdaddr_t *src, *dst;
+ char srcaddr[18], dstaddr[18];
bt_io_get(io, &gerr, BT_IO_OPT_SEC_LEVEL, &sec_level,
BT_IO_OPT_IMTU, &mtu,
@@ -5367,7 +6542,7 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
#endif
dev->att_mtu = MIN(mtu, BT_ATT_MAX_LE_MTU);
- attrib = g_attrib_new(io, dev->att_mtu);
+ attrib = g_attrib_new(io, dev->att_mtu, false);
if (!attrib) {
error("Unable to create new GAttrib instance");
return false;
@@ -5401,9 +6576,18 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
database = btd_adapter_get_database(dev->adapter);
+ src = btd_adapter_get_address(dev->adapter);
+ ba2str(src, srcaddr);
+
+ dst = device_get_address(dev);
+ ba2str(dst, dstaddr);
+
gatt_client_init(dev);
gatt_server_init(dev, btd_gatt_database_get_db(database));
+ if (gatt_db_isempty(dev->db))
+ load_gatt_db(dev, srcaddr, dstaddr);
+
/*
* Remove the device from the connect_list and give the passive
* scanning another chance to be restarted in case there are
@@ -5468,7 +6652,7 @@ done:
}
if (device->connect) {
- if (!device->le_state.svc_resolved)
+ if (!device->le_state.svc_resolved && !err)
device_browse_gatt(device, NULL);
if (err < 0)
@@ -5642,6 +6826,9 @@ static int device_browse_gatt(struct btd_device *device, DBusMessage *msg)
struct att_callbacks *attcb;
struct browse_req *req;
+#ifdef __TIZEN_PATCH__
+ DBG("");
+#endif
req = browse_request_new(device, msg);
if (!req)
return -EBUSY;
@@ -5720,6 +6907,9 @@ static int device_browse_sdp(struct btd_device *device, DBusMessage *msg)
uuid_t uuid;
int err;
+#ifdef __TIZEN_PATCH__
+ DBG("");
+#endif
req = browse_request_new(device, msg);
if (!req)
return -EBUSY;
@@ -5790,7 +6980,7 @@ void device_set_last_addr_type(struct btd_device *device, uint8_t type)
if (!device)
return;
- DBG("Last addr type %d", type);
+ //DBG("Last addr type %d", type);
device->last_bdaddr_type = type;
}
@@ -5841,6 +7031,31 @@ void device_le_data_length_changed(struct btd_device *device, uint16_t max_tx_oc
DBUS_TYPE_UINT16, &max_rx_time,
DBUS_TYPE_INVALID);
}
+
+const bdaddr_t *device_get_rpa(struct btd_device *device)
+{
+ return &device->rpa;
+}
+
+const uint8_t *device_get_irk_value(struct btd_device *device)
+{
+ return device->irk_val;
+}
+
+bool device_get_rpa_exist(struct btd_device *device)
+{
+ return device->rpa_exist;
+}
+
+void device_set_auth_addr_type(struct btd_device *device, uint8_t type)
+{
+ if (!device)
+ return;
+
+ DBG("Auth addr type %d", type);
+
+ device->auth_bdaddr_type = type;
+}
#endif
int device_discover_services(struct btd_device *device)
@@ -5929,6 +7144,30 @@ void btd_device_set_trusted(struct btd_device *device, gboolean trusted)
DEVICE_INTERFACE, "Trusted");
}
+#ifdef __TIZEN_PATCH__
+void btd_device_set_trusted_profiles(struct btd_device *device,
+ uint32_t pbap, uint32_t map, uint32_t sap)
+{
+ if (!device)
+ return;
+ DBG("TrustedProfiles Parameters: [PBAP %d] [MAP %d] [SAP %d]", pbap, map, sap);
+
+ if (device->trusted_profiles.pbap == pbap &&
+ device->trusted_profiles.map == map &&
+ device->trusted_profiles.sap == sap)
+ return;
+
+ device->trusted_profiles.pbap = pbap;
+ device->trusted_profiles.map = map;
+ device->trusted_profiles.sap = sap;
+
+ store_device_info(device);
+
+ g_dbus_emit_property_changed(dbus_conn, device->path,
+ DEVICE_INTERFACE, "TrustedProfiles");
+}
+#endif
+
void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type)
{
if (!device)
@@ -5960,7 +7199,8 @@ void device_set_legacy(struct btd_device *device, bool legacy)
DEVICE_INTERFACE, "LegacyPairing");
}
-void device_set_rssi(struct btd_device *device, int8_t rssi)
+void device_set_rssi_with_delta(struct btd_device *device, int8_t rssi,
+ int8_t delta_threshold)
{
if (!device)
return;
@@ -5989,8 +7229,8 @@ void device_set_rssi(struct btd_device *device, int8_t rssi)
else
delta = rssi - device->rssi;
- /* only report changes of 8 dBm or more */
- if (delta < 8)
+ /* only report changes of delta_threshold dBm or more */
+ if (delta < delta_threshold)
return;
DBG("rssi %d delta %d", rssi, delta);
@@ -6003,6 +7243,27 @@ void device_set_rssi(struct btd_device *device, int8_t rssi)
DEVICE_INTERFACE, "RSSI");
}
+void device_set_rssi(struct btd_device *device, int8_t rssi)
+{
+ device_set_rssi_with_delta(device, rssi, RSSI_THRESHOLD);
+}
+
+void device_set_tx_power(struct btd_device *device, int8_t tx_power)
+{
+ if (!device)
+ return;
+
+ if (device->tx_power == tx_power)
+ return;
+
+ DBG("tx_power %d", tx_power);
+
+ device->tx_power = tx_power;
+
+ g_dbus_emit_property_changed(dbus_conn, device->path,
+ DEVICE_INTERFACE, "TxPower");
+}
+
static gboolean start_discovery(gpointer user_data)
{
struct btd_device *device = user_data;
@@ -6125,11 +7386,19 @@ void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
if (state->paired) {
#ifdef __TIZEN_PATCH__
#ifdef TIZEN_WEARABLE
- DBG("Already paired. Send Paired Signal for Wearble syspopup termn");
- DBG("state->svc_resolved [%d]", state->svc_resolved);
- if (state->svc_resolved)
+ if (bdaddr_type == BDADDR_BREDR && state->svc_resolved) {
+ DBG("Link key has been changed. Report it");
+ if (device->rpa_exist == false)
+ g_dbus_emit_property_changed(dbus_conn, device->path,
+ DEVICE_INTERFACE, "Paired");
+ else
+ DBG("Just overwrite Link key");
+ } else if (bdaddr_type == BDADDR_LE_RANDOM ||
+ bdaddr_type == BDADDR_LE_PUBLIC) {
+ DBG("Long Term Key has been changed. Report it");
g_dbus_emit_property_changed(dbus_conn, device->path,
DEVICE_INTERFACE, "Paired");
+ }
#endif /* TIZEN_WEARABLE */
#endif /* __TIZEN_PATCH__ */
return;
@@ -6141,6 +7410,10 @@ void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
* request
*/
if (state->svc_resolved && bonding) {
+ /* Attept to store services for this device failed because it
+ * was not paired. Now that we're paired retry. */
+ store_gatt_db(device);
+
g_dbus_send_reply(dbus_conn, bonding->msg, DBUS_TYPE_INVALID);
bonding_request_free(bonding);
return;
@@ -6217,6 +7490,13 @@ unsigned int device_wait_for_svc_complete(struct btd_device *dev,
g_source_remove(dev->discov_timer);
dev->discov_timer = g_idle_add(start_discovery, dev);
}
+#ifdef __TIZEN_PATCH__
+ else if (!dev->browse) {
+ DBG("Service is not going on. Start discovery");
+ dev->discov_timer = g_idle_add(start_discovery, dev);
+ } else
+ DBG("Wait for service discovery");
+#endif
return cb->id;
}
@@ -6380,15 +7660,15 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *data)
return;
#ifdef __TIZEN_PATCH__
- if (device->bredr == TRUE)
- btd_adapter_confirm_reply(device->adapter, &device->bdaddr,
- BDADDR_BREDR,
- err ? FALSE : TRUE);
- else
-#endif
btd_adapter_confirm_reply(device->adapter, &device->bdaddr,
- device->bdaddr_type,
+ device->auth_bdaddr_type,
err ? FALSE : TRUE);
+ device_set_auth_addr_type(device, BDADDR_BREDR);
+#else
+ btd_adapter_confirm_reply(device->adapter, &device->bdaddr,
+ device->bdaddr_type,
+ err ? FALSE : TRUE);
+#endif
agent_unref(device->authr->agent);
device->authr->agent = NULL;
@@ -6407,8 +7687,14 @@ static void passkey_cb(struct agent *agent, DBusError *err,
if (err)
passkey = INVALID_PASSKEY;
+#ifdef __TIZEN_PATCH__
+ btd_adapter_passkey_reply(device->adapter, &device->bdaddr,
+ device->auth_bdaddr_type, passkey);
+ device_set_auth_addr_type(device, BDADDR_BREDR);
+#else
btd_adapter_passkey_reply(device->adapter, &device->bdaddr,
device->bdaddr_type, passkey);
+#endif
agent_unref(device->authr->agent);
device->authr->agent = NULL;
@@ -6628,12 +7914,23 @@ void device_cancel_authentication(struct btd_device *device, gboolean aborted)
cancel_authentication(auth);
device_auth_req_free(device);
+
+#ifdef __TIZEN_PATCH__
+ device_set_auth_addr_type(device, BDADDR_BREDR);
+#endif
}
+#ifdef __TIZEN_PATCH__
+gboolean device_is_authenticating(struct btd_device *dev, uint8_t bdaddr_type)
+{
+ return (dev->auth_bdaddr_type == bdaddr_type && dev->authr != NULL);
+}
+#else
gboolean device_is_authenticating(struct btd_device *device)
{
return (device->authr != NULL);
}
+#endif
struct gatt_primary *btd_device_get_primary(struct btd_device *device,
const char *uuid)
@@ -6720,6 +8017,11 @@ static sdp_list_t *read_device_records(struct btd_device *device)
ba2str(btd_adapter_get_address(device->adapter), local);
ba2str(&device->bdaddr, peer);
+#ifdef __TIZEN_PATCH__
+ if (device->rpa_exist)
+ ba2str(&device->rpa, peer);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
key_file = g_key_file_new();
@@ -6746,22 +8048,13 @@ static sdp_list_t *read_device_records(struct btd_device *device)
const sdp_record_t *btd_device_get_record(struct btd_device *device,
const char *uuid)
{
- if (device->tmp_records) {
- const sdp_record_t *record;
-
- record = find_record_in_list(device->tmp_records, uuid);
- if (record != NULL)
- return record;
-
- sdp_list_free(device->tmp_records,
- (sdp_free_func_t) sdp_record_free);
- device->tmp_records = NULL;
+ /* Load records from storage if there is nothing in cache */
+ if (!device->tmp_records) {
+ device->tmp_records = read_device_records(device);
+ if (!device->tmp_records)
+ return NULL;
}
- device->tmp_records = read_device_records(device);
- if (!device->tmp_records)
- return NULL;
-
return find_record_in_list(device->tmp_records, uuid);
}
@@ -6857,24 +8150,31 @@ void device_set_manufacturer_info(struct btd_device *device, struct eir_data *ei
void device_set_adv_report_info(struct btd_device *device, void *data, uint8_t data_len,
- uint8_t adv_type)
+ uint8_t adv_type, int8_t rssi)
{
if (!device)
return;
char peer_addr[18];
const char *paddr = peer_addr;
- dbus_int32_t rssi = device->rssi;
+ dbus_int32_t rssi_val = rssi;
int adv_len = data_len;
+ uint8_t addr_type;
ba2str(&device->bdaddr, peer_addr);
+ /* Replace address type for paired RPA device since IDA passed from controller */
+ if(device_get_rpa_exist(device) == true)
+ addr_type = BDADDR_LE_RANDOM;
+ else
+ addr_type = device->bdaddr_type;
+
g_dbus_emit_signal(dbus_conn, device->path,
DEVICE_INTERFACE, "AdvReport",
DBUS_TYPE_STRING, &paddr,
- DBUS_TYPE_BYTE, &device->bdaddr_type,
+ DBUS_TYPE_BYTE, &addr_type,
DBUS_TYPE_BYTE, &adv_type,
- DBUS_TYPE_INT32, &rssi,
+ DBUS_TYPE_INT32, &rssi_val,
DBUS_TYPE_INT32, &adv_len,
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len,
DBUS_TYPE_INVALID);
@@ -7069,7 +8369,11 @@ static void service_state_changed(struct btd_service *service,
#ifdef __TIZEN_PATCH__
if (!err) {
- g_dbus_emit_signal(dbus_conn, device->path,
+ if (old_state == BTD_SERVICE_STATE_UNAVAILABLE ||
+ new_state == BTD_SERVICE_STATE_UNAVAILABLE)
+ DBG("Skip status updating ([%d] -> [%d])", old_state, new_state);
+ else
+ g_dbus_emit_signal(dbus_conn, device->path,
DEVICE_INTERFACE, "ProfileStateChanged",
DBUS_TYPE_STRING, &profile->remote_uuid,
DBUS_TYPE_INT32, &new_state,
diff --git a/src/device.h b/src/device.h
index 65e5f5f2..d717c519 100644
--- a/src/device.h
+++ b/src/device.h
@@ -86,6 +86,8 @@ void btd_device_gatt_set_service_changed(struct btd_device *device,
bool device_attach_att(struct btd_device *dev, GIOChannel *io);
void btd_device_add_uuid(struct btd_device *device, const char *uuid);
void device_add_eir_uuids(struct btd_device *dev, GSList *uuids);
+void device_set_manufacturer_data(struct btd_device *dev, GSList *list);
+void device_set_service_data(struct btd_device *dev, GSList *list);
void device_probe_profile(gpointer a, gpointer b);
void device_remove_profile(gpointer a, gpointer b);
struct btd_adapter *device_get_adapter(struct btd_device *device);
@@ -100,6 +102,18 @@ void device_set_attrib(struct btd_device *device, guint attachid, GAttrib *attri
void device_unset_attrib(struct btd_device *device);
void device_unpair(struct btd_device *device, gboolean remove_stored);
gboolean device_get_gatt_connected(const struct btd_device *device);
+void device_set_rpa(struct btd_device *device, const bdaddr_t *rpa_addr);
+const bdaddr_t *device_get_rpa(struct btd_device *device);
+bool device_get_rpa_exist(struct btd_device *device);
+int device_rpa_cmp(gconstpointer a, gconstpointer b);
+int device_addr_cmp(gconstpointer a, gconstpointer b);
+void device_remove_stored_folder(struct btd_device *device);
+const uint8_t *device_get_irk_value(struct btd_device *device);
+void device_set_irk_value(struct btd_device *device, const char *val);
+void device_set_conn_update_state(struct btd_device *device, bool state);
+bool device_get_conn_update_state(struct btd_device *device);
+void btd_device_set_trusted_profiles(struct btd_device *device,
+ uint32_t pbap, uint32_t map, uint32_t sap);
#endif
gboolean device_is_temporary(struct btd_device *device);
bool device_is_paired(struct btd_device *device, uint8_t bdaddr_type);
@@ -111,7 +125,10 @@ void btd_device_set_temporary(struct btd_device *device, bool temporary);
void btd_device_set_trusted(struct btd_device *device, gboolean trusted);
void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type);
void device_set_legacy(struct btd_device *device, bool legacy);
+void device_set_rssi_with_delta(struct btd_device *device, int8_t rssi,
+ int8_t delta_threshold);
void device_set_rssi(struct btd_device *device, int8_t rssi);
+void device_set_tx_power(struct btd_device *device, int8_t tx_power);
bool btd_device_is_connected(struct btd_device *dev);
uint8_t btd_device_get_bdaddr_type(struct btd_device *dev);
bool device_is_retrying(struct btd_device *device);
@@ -133,10 +150,15 @@ int device_notify_passkey(struct btd_device *device, uint32_t passkey,
int device_notify_pincode(struct btd_device *device, gboolean secure,
const char *pincode);
void device_cancel_authentication(struct btd_device *device, gboolean aborted);
+#ifdef __TIZEN_PATCH__
+gboolean device_is_authenticating(struct btd_device *dev, uint8_t bdaddr_type);
+#else
gboolean device_is_authenticating(struct btd_device *device);
+#endif
void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type);
void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type);
void device_request_disconnect(struct btd_device *device, DBusMessage *msg);
+bool device_is_disconnecting(struct btd_device *device);
typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal,
void *user_data);
@@ -152,9 +174,10 @@ void device_set_appearance(struct btd_device *device, uint16_t value);
struct eir_data;
void device_set_manufacturer_info(struct btd_device *dev, struct eir_data *eir);
void device_set_adv_report_info(struct btd_device *device, void *data,
- uint8_t data_len, uint8_t adv_info);
+ uint8_t data_len, uint8_t adv_info, int8_t rssi);
void device_set_payload_timeout(struct btd_device *device,
uint16_t payload_timeout);
+void device_set_auth_addr_type(struct btd_device *device, uint8_t type);
void device_set_last_addr_type(struct btd_device *device, uint8_t type);
gboolean device_is_ipsp_connected(struct btd_device * device);
void device_set_ipsp_connected(struct btd_device *device, gboolean connected);
@@ -189,8 +212,15 @@ struct btd_service *btd_device_get_service(struct btd_device *dev,
const char *remote_uuid);
#ifdef __TIZEN_PATCH__
+gboolean device_is_profile_trusted(struct btd_device *device,
+ const char *uuid);
+gboolean device_is_profile_blocked(struct btd_device *device,
+ const char *uuid);
void btd_device_disconnect(struct btd_device *dev);
void btd_device_set_legacy_pairing(struct btd_device *dev, bool legacy_pairing);
+#ifdef TIZEN_WEARABLE
+void device_change_pkt_type(gpointer data, gpointer user_data);
+#endif /* TIZEN_WEARABLE */
#endif
int device_discover_services(struct btd_device *device);
diff --git a/src/eir.c b/src/eir.c
index 1fe7ff7d..3ef739b4 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -43,6 +43,14 @@
#define EIR_OOB_MIN (2 + 6)
+static void sd_free(void *data)
+{
+ struct eir_sd *sd = data;
+
+ free(sd->uuid);
+ g_free(sd);
+}
+
void eir_data_free(struct eir_data *eir)
{
g_slist_free_full(eir->services, free);
@@ -55,6 +63,8 @@ void eir_data_free(struct eir_data *eir)
eir->randomizer = NULL;
g_slist_free_full(eir->msd_list, g_free);
eir->msd_list = NULL;
+ g_slist_free_full(eir->sd_list, sd_free);
+ eir->sd_list = NULL;
#ifdef __TIZEN_PATCH__
g_free(eir->manufacturer_data);
eir->manufacturer_data = NULL;
@@ -180,6 +190,67 @@ static void eir_parse_msd(struct eir_data *eir, const uint8_t *data,
eir->msd_list = g_slist_append(eir->msd_list, msd);
}
+static void eir_parse_sd(struct eir_data *eir, uuid_t *service,
+ const uint8_t *data, uint8_t len)
+{
+ struct eir_sd *sd;
+ char *uuid;
+
+ uuid = bt_uuid2string(service);
+ if (!uuid)
+ return;
+
+ sd = g_malloc(sizeof(*sd));
+ sd->uuid = uuid;
+ sd->data_len = len;
+ memcpy(&sd->data, data, sd->data_len);
+
+ eir->sd_list = g_slist_append(eir->sd_list, sd);
+}
+
+static void eir_parse_uuid16_data(struct eir_data *eir, const uint8_t *data,
+ uint8_t len)
+{
+ uuid_t service;
+
+ if (len < 2 || len > EIR_SD_MAX_LEN)
+ return;
+
+ service.type = SDP_UUID16;
+ service.value.uuid16 = get_le16(data);
+ eir_parse_sd(eir, &service, data + 2, len - 2);
+}
+
+static void eir_parse_uuid32_data(struct eir_data *eir, const uint8_t *data,
+ uint8_t len)
+{
+ uuid_t service;
+
+ if (len < 4 || len > EIR_SD_MAX_LEN)
+ return;
+
+ service.type = SDP_UUID32;
+ service.value.uuid32 = get_le32(data);
+ eir_parse_sd(eir, &service, data + 4, len - 4);
+}
+
+static void eir_parse_uuid128_data(struct eir_data *eir, const uint8_t *data,
+ uint8_t len)
+{
+ uuid_t service;
+ int k;
+
+ if (len < 16 || len > EIR_SD_MAX_LEN)
+ return;
+
+ service.type = SDP_UUID128;
+
+ for (k = 0; k < 16; k++)
+ service.value.uuid128.data[k] = data[16 - k - 1];
+
+ eir_parse_sd(eir, &service, data + 16, len - 16);
+}
+
void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
{
uint16_t len = 0;
@@ -284,6 +355,18 @@ void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
eir->did_version = data[6] | (data[7] << 8);
break;
+ case EIR_SVC_DATA16:
+ eir_parse_uuid16_data(eir, data, data_len);
+ break;
+
+ case EIR_SVC_DATA32:
+ eir_parse_uuid32_data(eir, data, data_len);
+ break;
+
+ case EIR_SVC_DATA128:
+ eir_parse_uuid128_data(eir, data, data_len);
+ break;
+
case EIR_MANUFACTURER_DATA:
#ifdef __TIZEN_PATCH__
if (data_len < 1)
@@ -295,6 +378,7 @@ void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
#endif
eir_parse_msd(eir, data, data_len);
break;
+
}
eir_data += field_len + 1;
diff --git a/src/eir.h b/src/eir.h
index e906aa9f..423cb36f 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -22,6 +22,10 @@
*
*/
+#include <glib.h>
+
+#include "lib/sdp.h"
+
#define EIR_FLAGS 0x01 /* flags */
#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
@@ -36,7 +40,15 @@
#define EIR_SSP_HASH 0x0E /* SSP Hash */
#define EIR_SSP_RANDOMIZER 0x0F /* SSP Randomizer */
#define EIR_DEVICE_ID 0x10 /* device ID */
+#define EIR_SOLICIT16 0x14 /* LE: Solicit UUIDs, 16-bit */
+#define EIR_SOLICIT128 0x15 /* LE: Solicit UUIDs, 128-bit */
+#define EIR_SVC_DATA16 0x16 /* LE: Service data, 16-bit UUID */
+#define EIR_PUB_TRGT_ADDR 0x17 /* LE: Public Target Address */
+#define EIR_RND_TRGT_ADDR 0x18 /* LE: Random Target Address */
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
+#define EIR_SOLICIT32 0x1F /* LE: Solicit UUIDs, 32-bit */
+#define EIR_SVC_DATA32 0x20 /* LE: Service data, 32-bit UUID */
+#define EIR_SVC_DATA128 0x21 /* LE: Service data, 128-bit UUID */
#define EIR_MANUFACTURER_DATA 0xFF /* Manufacturer Specific Data */
/* Flags Descriptions */
@@ -48,6 +60,7 @@
#define EIR_SIM_HOST 0x10 /* Simultaneous LE and BR/EDR to Same
Device Capable (Host) */
+#define EIR_SD_MAX_LEN 238 /* 240 (EIR) - 2 (len) */
#define EIR_MSD_MAX_LEN 236 /* 240 (EIR) - 2 (len & type) - 2 */
struct eir_msd {
@@ -56,6 +69,12 @@ struct eir_msd {
uint8_t data_len;
};
+struct eir_sd {
+ char *uuid;
+ uint8_t data[EIR_SD_MAX_LEN];
+ uint8_t data_len;
+};
+
struct eir_data {
GSList *services;
unsigned int flags;
@@ -72,6 +91,7 @@ struct eir_data {
uint16_t did_version;
uint16_t did_source;
GSList *msd_list;
+ GSList *sd_list;
#ifdef __TIZEN_PATCH__
char *manufacturer_data;
uint8_t manufacturer_data_len;
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 00186878..8c1e1454 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -77,6 +77,9 @@ struct service {
bool chrcs_ready;
struct queue *pending_ext_props;
guint idle_id;
+#ifdef __TIZEN_PATCH__
+ guint idle_id2;
+#endif
};
struct characteristic {
@@ -447,9 +450,6 @@ static DBusMessage *descriptor_read_value(DBusConnection *conn,
return btd_error_in_progress(msg);
op = new0(struct async_dbus_op, 1);
- if (!op)
- return btd_error_failed(msg, "Failed to initialize request");
-
op->msg = dbus_message_ref(msg);
op->data = desc;
@@ -480,8 +480,20 @@ static void write_result_cb(bool success, bool reliable_error,
if (reliable_error)
reply = btd_error_failed(op->msg,
"Reliable write failed");
- else
+ else {
+#ifdef __TIZEN_PATCH__
+ reply = dbus_message_new_method_return(op->msg);
+ if (!reply) {
+ error("Failed to allocate D-Bus message reply");
+ return;
+ }
+ dbus_message_append_args(reply,
+ DBUS_TYPE_BYTE, &att_ecode,
+ DBUS_TYPE_INVALID);
+#else
reply = create_gatt_dbus_error(op->msg, att_ecode);
+#endif
+ }
goto done;
}
@@ -491,6 +503,11 @@ static void write_result_cb(bool success, bool reliable_error,
error("Failed to allocate D-Bus message reply");
return;
}
+#ifdef __TIZEN_PATCH__
+ dbus_message_append_args(reply,
+ DBUS_TYPE_BYTE, &att_ecode,
+ DBUS_TYPE_INVALID);
+#endif
done:
g_dbus_send_message(btd_get_dbus_connection(), reply);
@@ -512,9 +529,6 @@ static unsigned int start_long_write(DBusMessage *msg, uint16_t handle,
unsigned int id;
op = new0(struct async_dbus_op, 1);
- if (!op)
- return false;
-
op->msg = dbus_message_ref(msg);
op->data = data;
op->complete = complete;
@@ -540,9 +554,6 @@ static unsigned int start_write_request(DBusMessage *msg, uint16_t handle,
unsigned int id;
op = new0(struct async_dbus_op, 1);
- if (!op)
- return false;
-
op->msg = dbus_message_ref(msg);
op->data = data;
op->complete = complete;
@@ -556,11 +567,38 @@ static unsigned int start_write_request(DBusMessage *msg, uint16_t handle,
return id;
}
+#ifdef __TIZEN_PATCH__
+static unsigned int start_write_cmd(DBusMessage *msg, uint16_t handle,
+ struct bt_gatt_client *gatt, bool signed_write,
+ const uint8_t *value, size_t value_len,
+ void *data, async_dbus_op_complete_t complete)
+{
+ struct async_dbus_op *op;
+ unsigned int id;
+
+ op = new0(struct async_dbus_op, 1);
+ if (!op)
+ return 0;
+
+ op->msg = dbus_message_ref(msg);
+ op->data = data;
+ op->complete = complete;
+
+ id = bt_gatt_client_write_without_response_async(gatt, handle,
+ signed_write, value, value_len,
+ write_cb, op, async_dbus_op_free);
+ if (!id)
+ async_dbus_op_free(op);
+
+ return id;
+}
+#endif
+
static bool desc_write_complete(void *data)
{
struct descriptor *desc = data;
- desc->write_id = false;
+ desc->write_id = 0;
/*
* The descriptor might have been unregistered during the read. Return
@@ -637,8 +675,10 @@ static const GDBusMethodTable descriptor_methods[] = {
#ifdef __TIZEN_PATCH__
{ GDBUS_ASYNC_METHOD("ReadValue", NULL, GDBUS_ARGS({ "value", "ay" }),
descriptor_read_value) },
- { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }),
- NULL, descriptor_write_value) },
+ { GDBUS_ASYNC_METHOD("WriteValue",
+ GDBUS_ARGS({ "value", "ay" }),
+ GDBUS_ARGS({ "result", "y" }),
+ descriptor_write_value) },
{ }
#else
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL,
@@ -666,9 +706,6 @@ static struct descriptor *descriptor_create(struct gatt_db_attribute *attr,
struct descriptor *desc;
desc = new0(struct descriptor, 1);
- if (!desc)
- return NULL;
-
desc->chrc = chrc;
desc->attr = attr;
desc->handle = gatt_db_attribute_get_handle(attr);
@@ -763,7 +800,7 @@ static gboolean characteristic_value_exists(const GDBusPropertyTable *property,
gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_check_cb, &ret);
- return TRUE;
+ return ret;
}
static gboolean characteristic_get_notifying(const GDBusPropertyTable *property,
@@ -834,8 +871,10 @@ static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
if (err)
return;
- g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
- GATT_CHARACTERISTIC_IFACE, "Value");
+ g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
+ chrc->path, GATT_CHARACTERISTIC_IFACE,
+ "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
+
}
#ifdef __TIZEN_PATCH__
@@ -846,9 +885,6 @@ static void notify_characteristic_cb(struct gatt_db_attribute *attr, int err,
if (err)
return;
-
- g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
- GATT_CHARACTERISTIC_IFACE, "ChangedValue");
}
#endif
@@ -920,9 +956,6 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn,
return btd_error_in_progress(msg);
op = new0(struct async_dbus_op, 1);
- if (!op)
- return btd_error_failed(msg, "Failed to initialize request");
-
op->msg = dbus_message_ref(msg);
op->data = chrc;
@@ -942,7 +975,7 @@ static bool chrc_write_complete(void *data)
{
struct characteristic *chrc = data;
- chrc->write_id = false;
+ chrc->write_id = 0;
/*
* The characteristic might have been unregistered during the read.
@@ -1018,16 +1051,12 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
goto fail;
supported = true;
- chrc->write_id = bt_gatt_client_write_without_response(gatt,
+
+ if (bt_gatt_client_write_without_response(gatt,
chrc->value_handle,
chrc->props & BT_GATT_CHRC_PROP_AUTH,
- value, value_len);
- if (chrc->write_id) {
-#ifdef __TIZEN_PATCH__
- chrc->write_id = 0;
-#endif
+ value, value_len))
return dbus_message_new_method_return(msg);
- }
fail:
if (supported)
@@ -1058,7 +1087,6 @@ static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_WRITE) {
- DBG("BT_GATT_CHRC_PROP_WRITE");
uint16_t mtu;
supported = true;
mtu = bt_gatt_client_get_mtu(gatt);
@@ -1080,27 +1108,19 @@ static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
return NULL;
} else if ((write_type & chrc->props) ==
BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
- DBG("BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP");
supported = true;
- chrc->write_id = bt_gatt_client_write_without_response(gatt,
- chrc->value_handle,
- false,
- value, value_len);
- if (chrc->write_id) {
- chrc->write_id = 0;
- return dbus_message_new_method_return(msg);
- }
+ chrc->write_id = start_write_cmd(msg, chrc->value_handle, gatt,
+ false, value, value_len,
+ chrc, chrc_write_complete);
+ if (chrc->write_id)
+ return NULL;
} else if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_AUTH) {
- DBG("BT_GATT_CHRC_PROP_AUTH");
supported = true;
- chrc->write_id = bt_gatt_client_write_without_response(gatt,
- chrc->value_handle,
- true,
- value, value_len);
- if (chrc->write_id) {
- chrc->write_id = 0;
- return dbus_message_new_method_return(msg);
- }
+ chrc->write_id = start_write_cmd(msg, chrc->value_handle, gatt,
+ true, value, value_len,
+ chrc, chrc_write_complete);
+ if (chrc->write_id)
+ return NULL;
}
if (supported)
@@ -1193,9 +1213,6 @@ static struct notify_client *notify_client_create(struct characteristic *chrc,
struct notify_client *client;
client = new0(struct notify_client, 1);
- if (!client)
- return NULL;
-
client->chrc = chrc;
client->owner = strdup(owner);
if (!client->owner) {
@@ -1223,7 +1240,7 @@ static bool match_notify_sender(const void *a, const void *b)
return strcmp(client->owner, sender) == 0;
}
-#ifdef GATT_NO_RELAY
+#if defined __TIZEN_PATCH__ && defined GATT_NO_RELAY
struct char_value {
uint8_t *data;
uint8_t len;
@@ -1299,7 +1316,7 @@ static void notify_cb(uint16_t value_handle, const uint8_t *value,
gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
notify_characteristic_cb, chrc);
- gatt_characteristic_value_changed((void *)value, length, chrc);
+ gatt_characteristic_value_changed(value, length, chrc);
#else
gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
write_characteristic_cb, chrc);
@@ -1407,9 +1424,6 @@ static DBusMessage *characteristic_start_notify(DBusConnection *conn,
}
op = new0(struct async_dbus_op, 1);
- if (!op)
- goto fail;
-
op->data = client;
op->msg = dbus_message_ref(msg);
@@ -1521,7 +1535,8 @@ static const GDBusMethodTable characteristic_methods[] = {
NULL, characteristic_write_value) },
{ GDBUS_ASYNC_METHOD("WriteValuebyType",
GDBUS_ARGS({ "type", "y" }, { "value", "ay" }),
- NULL, characteristic_write_value_by_type) },
+ GDBUS_ARGS({ "result", "y" }),
+ characteristic_write_value_by_type) },
{ GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
characteristic_start_notify) },
{ GDBUS_METHOD("StopNotify", NULL, NULL, characteristic_stop_notify) },
@@ -1543,6 +1558,10 @@ static const GDBusMethodTable characteristic_methods[] = {
};
#ifdef __TIZEN_PATCH__
+static const GDBusSignalTable service_signals[] = {
+ { GDBUS_SIGNAL("GattServiceAdded",
+ GDBUS_ARGS({ "Service Path","s"})) },
+};
static const GDBusSignalTable characteristic_signals[] = {
{ GDBUS_SIGNAL("GattValueChanged",
GDBUS_ARGS({ "Result", "i"},
@@ -1571,22 +1590,8 @@ static struct characteristic *characteristic_create(
bt_uuid_t uuid;
chrc = new0(struct characteristic, 1);
- if (!chrc)
- return NULL;
-
chrc->descs = queue_new();
- if (!chrc->descs) {
- free(chrc);
- return NULL;
- }
-
chrc->notify_clients = queue_new();
- if (!chrc->notify_clients) {
- queue_destroy(chrc->descs, NULL);
- free(chrc);
- return NULL;
- }
-
chrc->service = service;
#ifndef __TIZEN_PATCH__
@@ -1768,22 +1773,8 @@ static struct service *service_create(struct gatt_db_attribute *attr,
bt_uuid_t uuid;
service = new0(struct service, 1);
- if (!service)
- return NULL;
-
service->chrcs = queue_new();
- if (!service->chrcs) {
- free(service);
- return NULL;
- }
-
service->pending_ext_props = queue_new();
- if (!service->pending_ext_props) {
- queue_destroy(service->chrcs, NULL);
- free(service);
- return NULL;
- }
-
service->client = client;
gatt_db_attribute_get_service_data(attr, &service->start_handle,
@@ -1797,11 +1788,15 @@ static struct service *service_create(struct gatt_db_attribute *attr,
if (!g_dbus_register_interface(btd_get_dbus_connection(), service->path,
GATT_SERVICE_IFACE,
+#ifdef __TIZEN_PATCH__
+ NULL, service_signals,
+#else
NULL, NULL,
+#endif
service_properties,
service, service_free)) {
error("Unable to register GATT service with handle 0x%04x for "
- "device %s:",
+ "device %s",
service->start_handle,
client->devaddr);
service_free(service);
@@ -1811,6 +1806,12 @@ static struct service *service_create(struct gatt_db_attribute *attr,
DBG("Exported GATT service: %s", service->path);
+ /* Set service active so we can skip discovering next time */
+ gatt_db_service_set_active(attr, true);
+
+ /* Mark the service as claimed since it going to be exported */
+ gatt_db_service_set_claimed(attr, true);
+
return service;
}
@@ -1823,6 +1824,11 @@ static void unregister_service(void *data)
if (service->idle_id)
g_source_remove(service->idle_id);
+#ifdef __TIZEN_PATCH__
+ if (service->idle_id2)
+ g_source_remove(service->idle_id2);
+#endif
+
queue_remove_all(service->chrcs, NULL, NULL, unregister_characteristic);
g_dbus_unregister_interface(btd_get_dbus_connection(), service->path,
@@ -1873,6 +1879,10 @@ static void read_ext_props_cb(bool success, uint8_t att_ecode,
struct characteristic *chrc = user_data;
struct service *service = chrc->service;
+#ifdef __TIZEN_PATCH__
+ chrc->read_id = 0;
+#endif
+
if (!success) {
error("Failed to obtain extended properties - error: 0x%02x",
att_ecode);
@@ -1900,10 +1910,17 @@ static void read_ext_props(void *data, void *user_data)
{
struct characteristic *chrc = data;
+#ifdef __TIZEN_PATCH__
+ chrc->read_id = bt_gatt_client_read_value(chrc->service->client->gatt,
+ chrc->ext_props_handle,
+ read_ext_props_cb,
+ chrc, NULL);
+#else
bt_gatt_client_read_value(chrc->service->client->gatt,
chrc->ext_props_handle,
read_ext_props_cb,
chrc, NULL);
+#endif
}
static bool create_descriptors(struct gatt_db_attribute *attr,
@@ -1971,11 +1988,34 @@ static gboolean set_chrcs_ready(gpointer user_data)
{
struct service *service = user_data;
+ service->idle_id = 0;
notify_chrcs(service);
return FALSE;
}
+#ifdef __TIZEN_PATCH__
+static gboolean notify_service_added_complete(gpointer user_data)
+{
+ struct service *service = user_data;
+ char *svc_path;
+
+ if (service == NULL || service->path == NULL)
+ return FALSE;
+
+ svc_path = g_strdup(service->path);
+
+ g_dbus_emit_signal(btd_get_dbus_connection(), service->path,
+ GATT_SERVICE_IFACE, "GattServiceAdded",
+ DBUS_TYPE_STRING, &svc_path,
+ DBUS_TYPE_INVALID);
+
+ g_free(svc_path);
+
+ return FALSE;
+}
+#endif
+
static void export_service(struct gatt_db_attribute *attr, void *user_data)
{
struct btd_gatt_client *client = user_data;
@@ -2003,6 +2043,11 @@ static void export_service(struct gatt_db_attribute *attr, void *user_data)
*/
if (!service->chrcs_ready && queue_isempty(service->pending_ext_props))
service->idle_id = g_idle_add(set_chrcs_ready, service);
+
+#ifdef __TIZEN_PATCH__
+ if (service->primary == true)
+ service->idle_id2 = g_idle_add(notify_service_added_complete, service);
+#endif
}
static void create_services(struct btd_gatt_client *client)
@@ -2025,22 +2070,8 @@ struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
return NULL;
client = new0(struct btd_gatt_client, 1);
- if (!client)
- return NULL;
-
client->services = queue_new();
- if (!client->services) {
- free(client);
- return NULL;
- }
-
client->all_notify_clients = queue_new();
- if (!client->all_notify_clients) {
- queue_destroy(client->services, NULL);
- free(client);
- return NULL;
- }
-
client->device = device;
ba2str(device_get_address(device), client->devaddr);
@@ -2074,9 +2105,6 @@ static void register_notify(void *data, void *user_data)
DBG("Re-register subscribed notification client");
op = new0(struct async_dbus_op, 1);
- if (!op)
- goto fail;
-
op->data = notify_client;
notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
@@ -2088,11 +2116,15 @@ static void register_notify(void *data, void *user_data)
async_dbus_op_free(op);
-fail:
DBG("Failed to re-register notification client");
+#ifdef __TIZEN_PATCH__
+ queue_remove(notify_client->chrc->notify_clients, notify_client);
+ queue_remove(client->all_notify_clients, notify_client);
+#else
queue_remove(notify_client->chrc->notify_clients, client);
queue_remove(client->all_notify_clients, client);
+#endif
notify_client_free(notify_client);
}
@@ -2123,14 +2155,22 @@ static gboolean check_all_chrcs_ready(gpointer user_data)
/*
* By adding below condition, forcing to call check_chrcs_ready()
* function to check whether all char./extended properties are ready.
- * Above function would be called max. for 20 times (Assuming more
- * no of services). Emit signal only when all characteristics are read.
+ * Above function would be called max. for 50 times (Assuming more
+ * no of services). Emit signal only when all characteristics are ready.
*/
- if (all_chrcs_ready == FALSE && count < 20) {
+ if (all_chrcs_ready == FALSE && count < 50) {
count++;
return TRUE;
}
+ /*
+ * There are chances when all of the primary services are not found,
+ * instead service changed is received while reading REQs in progress,
+ * so emit signal after service changed operation is completed (if any).
+ */
+ if (bt_gatt_client_svc_changed_received(client->gatt))
+ return TRUE;
+
device_set_gatt_connected(client->device, TRUE);
client->wait_charcs_id = 0;
@@ -2143,44 +2183,50 @@ static gboolean check_all_chrcs_ready(gpointer user_data)
void btd_gatt_client_ready(struct btd_gatt_client *client)
{
- struct bt_gatt_client *gatt;
-
if (!client)
return;
- gatt = btd_device_get_gatt_client(client->device);
- if (!gatt) {
+ if (!client->gatt) {
error("GATT client not initialized");
return;
}
- bt_gatt_client_unref(client->gatt);
- client->gatt = bt_gatt_client_ref(gatt);
-
client->ready = true;
DBG("GATT client ready");
- if (queue_isempty(client->services)) {
- DBG("Exporting services");
- create_services(client);
+ create_services(client);
#ifdef __TIZEN_PATCH__
/*
- * In case of more number of services and services having
- * characteristics extended properties; GattConnected signal
- * should be emitted only after all the characteristics are ready.
- * This piece of code checks all the characteristics periodically and
- * emit the signal if characteristics are ready.
- */
+ * In case of more number of services and services having
+ * characteristics extended properties; GattConnected signal
+ * should be emitted only after all the characteristics are ready.
+ * This piece of code checks all the characteristics periodically and
+ * emit the signal if characteristics are ready.
+ */
if (client->wait_charcs_id > 0)
g_source_remove(client->wait_charcs_id);
client->wait_charcs_id = g_timeout_add(100,
- check_all_chrcs_ready, client);
+ check_all_chrcs_ready, client);
#endif
+}
+
+void btd_gatt_client_connected(struct btd_gatt_client *client)
+{
+ struct bt_gatt_client *gatt;
+
+ gatt = btd_device_get_gatt_client(client->device);
+ if (!gatt) {
+ error("GATT client not initialized");
return;
}
+ DBG("Device connected.");
+
+ bt_gatt_client_unref(client->gatt);
+ client->gatt = bt_gatt_client_ref(gatt);
+
/*
* Services have already been created before. Re-enable notifications
* for any pre-registered notification sessions.
@@ -2282,24 +2328,49 @@ void btd_gatt_client_disconnected(struct btd_gatt_client *client)
DBG("Device disconnected. Cleaning up.");
+#ifdef __TIZEN_PATCH__
+ if (client->wait_charcs_id) {
+ g_source_remove(client->wait_charcs_id);
+ client->wait_charcs_id = 0;
+ }
+#endif
+
/*
- * Remove all services. We'll recreate them when a new bt_gatt_client
- * becomes ready. Leave the services around if the device is bonded.
* TODO: Once GATT over BR/EDR is properly supported, we should pass the
* correct bdaddr_type based on the transport over which GATT is being
* done.
*/
- if (!device_is_bonded(client->device, BDADDR_LE_PUBLIC)) {
- DBG("Device not bonded. Removing exported services.");
- queue_remove_all(client->services, NULL, NULL,
- unregister_service);
- } else {
- DBG("Device is bonded. Keeping exported services up.");
- queue_foreach(client->all_notify_clients, clear_notify_id,
- NULL);
- queue_foreach(client->services, cancel_ops, client->gatt);
- }
+ queue_foreach(client->all_notify_clients, clear_notify_id, NULL);
+ queue_foreach(client->services, cancel_ops, client->gatt);
bt_gatt_client_unref(client->gatt);
client->gatt = NULL;
}
+
+struct foreach_service_data {
+ btd_gatt_client_service_path_t func;
+ void *user_data;
+};
+
+static void client_service_foreach(void *data, void *user_data)
+{
+ struct service *service = data;
+ struct foreach_service_data *foreach_data = user_data;
+
+ foreach_data->func(service->path, foreach_data->user_data);
+}
+
+void btd_gatt_client_foreach_service(struct btd_gatt_client *client,
+ btd_gatt_client_service_path_t func,
+ void *user_data)
+{
+ struct foreach_service_data data;
+
+ if (!client)
+ return;
+
+ data.func = func;
+ data.user_data = user_data;
+
+ queue_foreach(client->services, client_service_foreach, &data);
+}
diff --git a/src/gatt-client.h b/src/gatt-client.h
index f6da3b07..92a92554 100644
--- a/src/gatt-client.h
+++ b/src/gatt-client.h
@@ -23,8 +23,15 @@ struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device);
void btd_gatt_client_destroy(struct btd_gatt_client *client);
void btd_gatt_client_ready(struct btd_gatt_client *client);
+void btd_gatt_client_connected(struct btd_gatt_client *client);
void btd_gatt_client_service_added(struct btd_gatt_client *client,
struct gatt_db_attribute *attrib);
void btd_gatt_client_service_removed(struct btd_gatt_client *client,
struct gatt_db_attribute *attrib);
void btd_gatt_client_disconnected(struct btd_gatt_client *client);
+
+typedef void (*btd_gatt_client_service_path_t)(const char *service_path,
+ void *user_data);
+void btd_gatt_client_foreach_service(struct btd_gatt_client *client,
+ btd_gatt_client_service_path_t func,
+ void *user_data);
diff --git a/src/gatt-database.c b/src/gatt-database.c
index e360cde1..c0386941 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -43,6 +43,7 @@
#include "gatt-database.h"
#include "dbus-common.h"
#include "profile.h"
+#include "service.h"
#ifndef ATT_CID
#define ATT_CID 4
@@ -76,17 +77,23 @@ struct btd_gatt_database {
struct queue *ccc_callbacks;
struct gatt_db_attribute *svc_chngd;
struct gatt_db_attribute *svc_chngd_ccc;
- struct queue *services;
+ struct queue *apps;
struct queue *profiles;
};
-struct external_service {
+struct gatt_app {
struct btd_gatt_database *database;
- bool failed;
char *owner;
- char *path; /* Path to GattService1 */
+ char *path;
DBusMessage *reg;
GDBusClient *client;
+ bool failed;
+ struct queue *services;
+};
+
+struct external_service {
+ struct gatt_app *app;
+ char *path; /* Path to GattService1 */
GDBusProxy *proxy;
struct gatt_db_attribute *attrib;
uint16_t attr_cnt;
@@ -119,6 +126,7 @@ struct external_desc {
struct external_service *service;
char *chrc_path;
GDBusProxy *proxy;
+ uint32_t perm;
struct gatt_db_attribute *attrib;
bool handled;
struct queue *pending_reads;
@@ -258,15 +266,7 @@ static struct device_state *device_state_create(bdaddr_t *bdaddr,
struct device_state *dev_state;
dev_state = new0(struct device_state, 1);
- if (!dev_state)
- return NULL;
-
dev_state->ccc_states = queue_new();
- if (!dev_state->ccc_states) {
- free(dev_state);
- return NULL;
- }
-
bacpy(&dev_state->bdaddr, bdaddr);
dev_state->bdaddr_type = bdaddr_type;
@@ -288,8 +288,6 @@ static struct device_state *get_device_state(struct btd_gatt_database *database,
return dev_state;
dev_state = device_state_create(bdaddr, bdaddr_type);
- if (!dev_state)
- return NULL;
queue_push_tail(database->device_states, dev_state);
@@ -305,17 +303,12 @@ static struct ccc_state *get_ccc_state(struct btd_gatt_database *database,
struct ccc_state *ccc;
dev_state = get_device_state(database, bdaddr, bdaddr_type);
- if (!dev_state)
- return NULL;
ccc = find_ccc_state(dev_state, handle);
if (ccc)
return ccc;
ccc = new0(struct ccc_state, 1);
- if (!ccc)
- return NULL;
-
ccc->handle = handle;
queue_push_tail(dev_state->ccc_states, ccc);
@@ -384,26 +377,41 @@ static void service_free(void *data)
queue_destroy(service->chrcs, chrc_free);
queue_destroy(service->descs, desc_free);
- gatt_db_remove_service(service->database->db, service->attrib);
+ if (service->attrib)
+ gatt_db_remove_service(service->app->database->db,
+ service->attrib);
- if (service->client) {
- g_dbus_client_set_disconnect_watch(service->client, NULL, NULL);
- g_dbus_client_set_proxy_handlers(service->client, NULL, NULL,
- NULL, NULL);
- g_dbus_client_set_ready_watch(service->client, NULL, NULL);
+ if (service->app->client)
g_dbus_proxy_unref(service->proxy);
- g_dbus_client_unref(service->client);
- }
- if (service->reg)
- dbus_message_unref(service->reg);
-
- g_free(service->owner);
g_free(service->path);
free(service);
}
+static void app_free(void *data)
+{
+ struct gatt_app *app = data;
+
+ queue_destroy(app->services, service_free);
+
+ if (app->client) {
+ g_dbus_client_set_disconnect_watch(app->client, NULL, NULL);
+ g_dbus_client_set_proxy_handlers(app->client, NULL, NULL,
+ NULL, NULL);
+ g_dbus_client_set_ready_watch(app->client, NULL, NULL);
+ g_dbus_client_unref(app->client);
+ }
+
+ if (app->reg)
+ dbus_message_unref(app->reg);
+
+ g_free(app->owner);
+ g_free(app->path);
+
+ free(app);
+}
+
static void profile_remove(void *data)
{
struct btd_profile *p = data;
@@ -411,6 +419,7 @@ static void profile_remove(void *data)
DBG("Removed \"%s\"", p->name);
adapter_foreach(adapter_remove_profile, p);
+ btd_profile_unregister(p);
g_free((void *) p->name);
g_free((void *) p->remote_uuid);
@@ -475,7 +484,7 @@ static void gatt_database_free(void *data)
gatt_db_unregister(database->db, database->db_id);
queue_destroy(database->device_states, device_state_free);
- queue_destroy(database->services, service_free);
+ queue_destroy(database->apps, app_free);
queue_destroy(database->profiles, profile_free);
queue_destroy(database->ccc_callbacks, ccc_cb_free);
database->device_states = NULL;
@@ -522,6 +531,13 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
device_attach_att(device, io);
}
+#ifdef __TIZEN_PATCH__
+#define LE_BEARER_POSTFIX " LE"
+#define LE_BEARER_POSTFIX_LEN 3
+
+static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type);
+#endif
+
static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
@@ -532,10 +548,30 @@ static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
size_t len = 0;
const uint8_t *value = NULL;
const char *device_name;
+#ifdef __TIZEN_PATCH__
+ bdaddr_t dst = { { 0 } };
+ uint8_t dst_type = 0;
+ char le_name[MAX_NAME_LENGTH + 1];
+#endif
DBG("GAP Device Name read request\n");
device_name = btd_adapter_get_name(database->adapter);
+#ifdef __TIZEN_PATCH__
+ if (get_dst_info(att, &dst, &dst_type) && dst_type != BDADDR_BREDR) {
+ char *ptr = NULL;
+
+ g_strlcpy(le_name, device_name,
+ sizeof(le_name) - LE_BEARER_POSTFIX_LEN);
+ if (!g_utf8_validate(le_name, -1, (const char **)&ptr))
+ *ptr = '\0';
+
+ g_strlcat(le_name, LE_BEARER_POSTFIX, sizeof(le_name));
+ DBG("Append LE bearer postfix : %s", le_name);
+
+ device_name = le_name;
+ }
+#endif
len = strlen(device_name);
if (offset > len) {
@@ -795,10 +831,6 @@ static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
}
ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
- if (!ccc) {
- ecode = BT_ATT_ERROR_UNLIKELY;
- goto done;
- }
len = 2 - offset;
value = len ? &ccc->value[offset] : NULL;
@@ -841,10 +873,6 @@ static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
}
ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
- if (!ccc) {
- ecode = BT_ATT_ERROR_UNLIKELY;
- goto done;
- }
ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle,
UINT_TO_PTR(gatt_db_attribute_get_handle(attrib)));
@@ -881,10 +909,6 @@ service_add_ccc(struct gatt_db_attribute *service,
bt_uuid_t uuid;
ccc_cb = new0(struct ccc_cb_data, 1);
- if (!ccc_cb) {
- error("Could not allocate memory for callback data");
- return NULL;
- }
bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
ccc = gatt_db_service_add_descriptor(service, &uuid,
@@ -1274,159 +1298,338 @@ struct svc_match_data {
const char *sender;
};
-static bool match_service(const void *a, const void *b)
+static bool match_app(const void *a, const void *b)
{
- const struct external_service *service = a;
+ const struct gatt_app *app = a;
const struct svc_match_data *data = b;
- return g_strcmp0(service->path, data->path) == 0 &&
- g_strcmp0(service->owner, data->sender) == 0;
+ return g_strcmp0(app->path, data->path) == 0 &&
+ g_strcmp0(app->owner, data->sender) == 0;
}
-static gboolean service_free_idle_cb(void *data)
+static gboolean app_free_idle_cb(void *data)
{
- service_free(data);
+ app_free(data);
return FALSE;
}
-static void service_remove_helper(void *data)
-{
- struct external_service *service = data;
-
- queue_remove(service->database->services, service);
-
- /*
- * Do not run in the same loop, this may be a disconnect
- * watch call and GDBusClient should not be destroyed.
- */
- g_idle_add(service_free_idle_cb, service);
-}
-
static void client_disconnect_cb(DBusConnection *conn, void *user_data)
{
+ struct gatt_app *app = user_data;
+ struct btd_gatt_database *database = app->database;
+
DBG("Client disconnected");
- service_remove_helper(user_data);
+ if (queue_remove(database->apps, app))
+ app_free(app);
}
-static void service_remove(void *data)
+static void remove_app(void *data)
{
- struct external_service *service = data;
+ struct gatt_app *app = data;
/*
* Set callback to NULL to avoid potential race condition
- * when calling remove_service and GDBusClient unref.
+ * when calling remove_app and GDBusClient unref.
*/
- g_dbus_client_set_disconnect_watch(service->client, NULL, NULL);
+ g_dbus_client_set_disconnect_watch(app->client, NULL, NULL);
/*
* Set proxy handlers to NULL, so that this gets called only once when
* the first proxy that belongs to this service gets removed.
*/
- g_dbus_client_set_proxy_handlers(service->client, NULL, NULL,
- NULL, NULL);
+ g_dbus_client_set_proxy_handlers(app->client, NULL, NULL, NULL, NULL);
+
- service_remove_helper(service);
+ queue_remove(app->database->apps, app);
+
+ /*
+ * Do not run in the same loop, this may be a disconnect
+ * watch call and GDBusClient should not be destroyed.
+ */
+ g_idle_add(app_free_idle_cb, app);
+}
+
+static bool match_service_by_path(const void *a, const void *b)
+{
+ const struct external_service *service = a;
+ const char *path = b;
+
+ return strcmp(service->path, path) == 0;
}
-static struct external_chrc *chrc_create(struct external_service *service,
+static bool parse_path(GDBusProxy *proxy, const char *name, const char **path)
+{
+ DBusMessageIter iter;
+
+ if (!g_dbus_proxy_get_property(proxy, name, &iter))
+ return false;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+ return false;
+
+ dbus_message_iter_get_basic(&iter, path);
+
+ return true;
+}
+
+static bool incr_attr_count(struct external_service *service, uint16_t incr)
+{
+ if (service->attr_cnt > UINT16_MAX - incr)
+ return false;
+
+ service->attr_cnt += incr;
+
+ return true;
+}
+
+static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props,
+ uint8_t *ext_props)
+{
+ const char *flag;
+
+ *props = *ext_props = 0;
+
+ do {
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(array, &flag);
+
+ if (!strcmp("broadcast", flag))
+ *props |= BT_GATT_CHRC_PROP_BROADCAST;
+ else if (!strcmp("read", flag))
+ *props |= BT_GATT_CHRC_PROP_READ;
+ else if (!strcmp("write-without-response", flag))
+ *props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP;
+ else if (!strcmp("write", flag))
+ *props |= BT_GATT_CHRC_PROP_WRITE;
+ else if (!strcmp("notify", flag))
+ *props |= BT_GATT_CHRC_PROP_NOTIFY;
+ else if (!strcmp("indicate", flag))
+ *props |= BT_GATT_CHRC_PROP_INDICATE;
+ else if (!strcmp("authenticated-signed-writes", flag))
+ *props |= BT_GATT_CHRC_PROP_AUTH;
+ else if (!strcmp("reliable-write", flag))
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
+ else if (!strcmp("writable-auxiliaries", flag))
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX;
+ else if (!strcmp("encrypt-read", flag)) {
+ *props |= BT_GATT_CHRC_PROP_READ;
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_READ;
+ } else if (!strcmp("encrypt-write", flag)) {
+ *props |= BT_GATT_CHRC_PROP_WRITE;
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_WRITE;
+ } else if (!strcmp("encrypt-authenticated-read", flag)) {
+ *props |= BT_GATT_CHRC_PROP_READ;
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
+ } else if (!strcmp("encrypt-authenticated-write", flag)) {
+ *props |= BT_GATT_CHRC_PROP_WRITE;
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
+ } else {
+ error("Invalid characteristic flag: %s", flag);
+ return false;
+ }
+ } while (dbus_message_iter_next(array));
+
+ if (*ext_props)
+ *props |= BT_GATT_CHRC_PROP_EXT_PROP;
+
+ return true;
+}
+
+static bool parse_desc_flags(DBusMessageIter *array, uint32_t *perm)
+{
+ const char *flag;
+
+ *perm = 0;
+
+ do {
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(array, &flag);
+
+ if (!strcmp("read", flag))
+ *perm |= BT_ATT_PERM_READ;
+ else if (!strcmp("write", flag))
+ *perm |= BT_ATT_PERM_WRITE;
+ else if (!strcmp("encrypt-read", flag))
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT;
+ else if (!strcmp("encrypt-write", flag))
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_ENCRYPT;
+ else if (!strcmp("encrypt-authenticated-read", flag))
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
+ else if (!strcmp("encrypt-authenticated-write", flag))
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
+ else {
+ error("Invalid descriptor flag: %s", flag);
+ return false;
+ }
+ } while (dbus_message_iter_next(array));
+
+ return true;
+}
+
+static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props,
+ uint32_t *perm)
+{
+ DBusMessageIter iter, array;
+
+ if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
+ return false;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&iter, &array);
+
+ if (perm)
+ return parse_desc_flags(&array, perm);
+
+ return parse_chrc_flags(&array, props, ext_props);
+}
+
+static struct external_chrc *chrc_create(struct gatt_app *app,
GDBusProxy *proxy,
const char *path)
{
+ struct external_service *service;
struct external_chrc *chrc;
+ const char *service_path;
- chrc = new0(struct external_chrc, 1);
- if (!chrc)
+ if (!parse_path(proxy, "Service", &service_path)) {
+ error("Failed to obtain service path for characteristic");
return NULL;
+ }
- chrc->pending_reads = queue_new();
- if (!chrc->pending_reads) {
- free(chrc);
+ service = queue_find(app->services, match_service_by_path,
+ service_path);
+ if (!service) {
+ error("Unable to find service for characteristic: %s", path);
return NULL;
}
+ chrc = new0(struct external_chrc, 1);
+ chrc->pending_reads = queue_new();
chrc->pending_writes = queue_new();
- if (!chrc->pending_writes) {
- queue_destroy(chrc->pending_reads, NULL);
- free(chrc);
- return NULL;
- }
chrc->path = g_strdup(path);
- if (!chrc->path) {
- queue_destroy(chrc->pending_reads, NULL);
- queue_destroy(chrc->pending_writes, NULL);
- free(chrc);
- return NULL;
- }
+ if (!chrc->path)
+ goto fail;
chrc->service = service;
chrc->proxy = g_dbus_proxy_ref(proxy);
+ /*
+ * Add 2 for the characteristic declaration and the value
+ * attribute.
+ */
+ if (!incr_attr_count(chrc->service, 2)) {
+ error("Failed to increment attribute count");
+ goto fail;
+ }
+
+ /*
+ * Parse characteristic flags (i.e. properties) here since they
+ * are used to determine if any special descriptors should be
+ * created.
+ */
+ if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, NULL)) {
+ error("Failed to parse characteristic properties");
+ goto fail;
+ }
+
+ if ((chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
+ chrc->props & BT_GATT_CHRC_PROP_INDICATE) &&
+ !incr_attr_count(chrc->service, 1)) {
+ error("Failed to increment attribute count for CCC");
+ goto fail;
+ }
+
+ if (chrc->ext_props && !incr_attr_count(chrc->service, 1)) {
+ error("Failed to increment attribute count for CEP");
+ goto fail;
+ }
+
+ queue_push_tail(chrc->service->chrcs, chrc);
+
return chrc;
+
+fail:
+ chrc_free(chrc);
+ return NULL;
}
-static struct external_desc *desc_create(struct external_service *service,
- GDBusProxy *proxy,
- const char *chrc_path)
+static bool match_chrc(const void *a, const void *b)
+{
+ const struct external_chrc *chrc = a;
+ const char *path = b;
+
+ return strcmp(chrc->path, path) == 0;
+}
+
+static bool match_service_by_chrc(const void *a, const void *b)
{
+ const struct external_service *service = a;
+ const char *path = b;
+
+ return queue_find(service->chrcs, match_chrc, path);
+}
+
+static struct external_desc *desc_create(struct gatt_app *app,
+ GDBusProxy *proxy)
+{
+ struct external_service *service;
struct external_desc *desc;
+ const char *chrc_path;
- desc = new0(struct external_desc, 1);
- if (!desc)
+ if (!parse_path(proxy, "Characteristic", &chrc_path)) {
+ error("Failed to obtain characteristic path for descriptor");
return NULL;
+ }
- desc->pending_reads = queue_new();
- if (!desc->pending_reads) {
- free(desc);
+ service = queue_find(app->services, match_service_by_chrc, chrc_path);
+ if (!service) {
+ error("Unable to find service for characteristic: %s",
+ chrc_path);
return NULL;
}
+ desc = new0(struct external_desc, 1);
+ desc->pending_reads = queue_new();
desc->pending_writes = queue_new();
- if (!desc->pending_writes) {
- queue_destroy(desc->pending_reads, NULL);
- free(desc);
- return NULL;
- }
desc->chrc_path = g_strdup(chrc_path);
- if (!desc->chrc_path) {
- queue_destroy(desc->pending_reads, NULL);
- queue_destroy(desc->pending_writes, NULL);
- free(desc);
- return NULL;
- }
+ if (!desc->chrc_path)
+ goto fail;
desc->service = service;
desc->proxy = g_dbus_proxy_ref(proxy);
- return desc;
-}
-
-static bool incr_attr_count(struct external_service *service, uint16_t incr)
-{
- if (service->attr_cnt > UINT16_MAX - incr)
- return false;
-
- service->attr_cnt += incr;
-
- return true;
-}
+ /* Add 1 for the descriptor attribute */
+ if (!incr_attr_count(desc->service, 1)) {
+ error("Failed to increment attribute count");
+ goto fail;
+ }
-static bool parse_path(GDBusProxy *proxy, const char *name, const char **path)
-{
- DBusMessageIter iter;
+ /*
+ * Parse descriptors flags here since they are used to
+ * determine the permission the descriptor should have
+ */
+ if (!parse_flags(proxy, NULL, NULL, &desc->perm)) {
+ error("Failed to parse characteristic properties");
+ goto fail;
+ }
- if (!g_dbus_proxy_get_property(proxy, name, &iter))
- return false;
+ queue_push_tail(desc->service->descs, desc);
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
- return false;
-
- dbus_message_iter_get_basic(&iter, path);
+ return desc;
- return true;
+fail:
+ desc_free(desc);
+ return NULL;
}
static bool check_service_path(GDBusProxy *proxy,
@@ -1440,190 +1643,107 @@ static bool check_service_path(GDBusProxy *proxy,
return g_strcmp0(service_path, service->path) == 0;
}
-static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props)
+static struct external_service *create_service(struct gatt_app *app,
+ GDBusProxy *proxy,
+ const char *path)
{
- DBusMessageIter iter, array;
- const char *flag;
+ struct external_service *service;
- *props = *ext_props = 0;
+ if (!path || !g_str_has_prefix(path, "/"))
+ return NULL;
- if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
- return false;
+ service = queue_find(app->services, match_service_by_path, path);
+ if (service) {
+ error("Duplicated service: %s", path);
+ return NULL;
+ }
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- return false;
+ service = new0(struct external_service, 1);
- dbus_message_iter_recurse(&iter, &array);
+ service->app = app;
- do {
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING)
- return false;
+ service->path = g_strdup(path);
+ if (!service->path)
+ goto fail;
- dbus_message_iter_get_basic(&array, &flag);
+ service->proxy = g_dbus_proxy_ref(proxy);
+ service->chrcs = queue_new();
+ service->descs = queue_new();
- if (!strcmp("broadcast", flag))
- *props |= BT_GATT_CHRC_PROP_BROADCAST;
- else if (!strcmp("read", flag))
- *props |= BT_GATT_CHRC_PROP_READ;
- else if (!strcmp("write-without-response", flag))
- *props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP;
- else if (!strcmp("write", flag))
- *props |= BT_GATT_CHRC_PROP_WRITE;
- else if (!strcmp("notify", flag))
- *props |= BT_GATT_CHRC_PROP_NOTIFY;
- else if (!strcmp("indicate", flag))
- *props |= BT_GATT_CHRC_PROP_INDICATE;
- else if (!strcmp("authenticated-signed-writes", flag))
- *props |= BT_GATT_CHRC_PROP_AUTH;
- else if (!strcmp("reliable-write", flag))
- *ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
- else if (!strcmp("writable-auxiliaries", flag))
- *ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX;
- else {
- error("Invalid characteristic flag: %s", flag);
- return false;
- }
- } while (dbus_message_iter_next(&array));
+ /* Add 1 for the service declaration */
+ if (!incr_attr_count(service, 1)) {
+ error("Failed to increment attribute count");
+ goto fail;
+ }
- if (*ext_props)
- *props |= BT_GATT_CHRC_PROP_EXT_PROP;
+ queue_push_tail(app->services, service);
- return true;
+ return service;
+
+fail:
+ service_free(service);
+ return NULL;
}
static void proxy_added_cb(GDBusProxy *proxy, void *user_data)
{
- struct external_service *service = user_data;
+ struct gatt_app *app = user_data;
const char *iface, *path;
- if (service->failed || service->attrib)
+ if (app->failed)
return;
iface = g_dbus_proxy_get_interface(proxy);
path = g_dbus_proxy_get_path(proxy);
- if (!g_str_has_prefix(path, service->path))
- return;
-
if (g_strcmp0(iface, GATT_SERVICE_IFACE) == 0) {
- if (service->proxy)
- return;
-
- /*
- * TODO: We may want to support adding included services in a
- * single hierarchy.
- */
- if (g_strcmp0(path, service->path) != 0) {
- error("Multiple services added within hierarchy");
- service->failed = true;
- return;
- }
+ struct external_service *service;
- /* Add 1 for the service declaration */
- if (!incr_attr_count(service, 1)) {
- error("Failed to increment attribute count");
- service->failed = true;
+ service = create_service(app, proxy, path);
+ if (!service) {
+ app->failed = true;
return;
}
-
- service->proxy = g_dbus_proxy_ref(proxy);
} else if (g_strcmp0(iface, GATT_CHRC_IFACE) == 0) {
struct external_chrc *chrc;
- if (g_strcmp0(path, service->path) == 0) {
- error("Characteristic path same as service path");
- service->failed = true;
- return;
- }
-
- chrc = chrc_create(service, proxy, path);
+ chrc = chrc_create(app, proxy, path);
if (!chrc) {
- service->failed = true;
- return;
- }
-
- /*
- * Add 2 for the characteristic declaration and the value
- * attribute.
- */
- if (!incr_attr_count(service, 2)) {
- error("Failed to increment attribute count");
- service->failed = true;
- return;
- }
-
- /*
- * Parse characteristic flags (i.e. properties) here since they
- * are used to determine if any special descriptors should be
- * created.
- */
- if (!parse_flags(proxy, &chrc->props, &chrc->ext_props)) {
- error("Failed to parse characteristic properties");
- service->failed = true;
+ app->failed = true;
return;
}
-
- if ((chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
- chrc->props & BT_GATT_CHRC_PROP_INDICATE) &&
- !incr_attr_count(service, 1)) {
- error("Failed to increment attribute count for CCC");
- service->failed = true;
- return;
- }
-
- if (chrc->ext_props && !incr_attr_count(service, 1)) {
- error("Failed to increment attribute count for CEP");
- service->failed = true;
- return;
- }
-
- queue_push_tail(service->chrcs, chrc);
} else if (g_strcmp0(iface, GATT_DESC_IFACE) == 0) {
struct external_desc *desc;
- const char *chrc_path;
- if (!parse_path(proxy, "Characteristic", &chrc_path)) {
- error("Failed to obtain characteristic path for "
- "descriptor");
- service->failed = true;
- return;
- }
-
- desc = desc_create(service, proxy, chrc_path);
+ desc = desc_create(app, proxy);
if (!desc) {
- service->failed = true;
- return;
- }
-
- /* Add 1 for the descriptor attribute */
- if (!incr_attr_count(service, 1)) {
- error("Failed to increment attribute count");
- service->failed = true;
+ app->failed = true;
return;
}
-
- queue_push_tail(service->descs, desc);
} else {
DBG("Ignoring unrelated interface: %s", iface);
return;
}
- DBG("Object added to service - path: %s, iface: %s", path, iface);
+ DBG("Object added: path: %s, iface: %s", path, iface);
}
static void proxy_removed_cb(GDBusProxy *proxy, void *user_data)
{
- struct external_service *service = user_data;
+ struct gatt_app *app = user_data;
+ struct external_service *service;
const char *path;
path = g_dbus_proxy_get_path(proxy);
- if (!g_str_has_prefix(path, service->path))
+ service = queue_remove_if(app->services, match_service_by_path,
+ (void *) path);
+ if (!service)
return;
DBG("Proxy removed - removing service: %s", service->path);
- service_remove(service);
+ service_free(service);
}
static bool parse_uuid(GDBusProxy *proxy, bt_uuid_t *uuid)
@@ -1679,7 +1799,6 @@ static bool parse_primary(GDBusProxy *proxy, bool *primary)
static uint8_t dbus_error_to_att_ecode(const char *error_name)
{
- /* TODO: Parse error ATT ecode from error_message */
if (strcmp(error_name, "org.bluez.Error.Failed") == 0)
return 0x80; /* For now return this "application error" */
@@ -1693,6 +1812,9 @@ static uint8_t dbus_error_to_att_ecode(const char *error_name)
if (strcmp(error_name, "org.bluez.Error.InvalidValueLength") == 0)
return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+ if (strcmp(error_name, "org.bluez.Error.InProgress") == 0)
+ return BT_ERROR_ALREADY_IN_PROGRESS;
+
return 0;
}
@@ -2015,12 +2137,28 @@ static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props)
if (props & BT_GATT_CHRC_PROP_WRITE ||
props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP ||
- ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)
+ ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE ||
+ ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE ||
+ ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
perm |= BT_ATT_PERM_WRITE;
- if (props & BT_GATT_CHRC_PROP_READ)
+ if (props & BT_GATT_CHRC_PROP_READ ||
+ ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ ||
+ ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ)
perm |= BT_ATT_PERM_READ;
+ if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ)
+ perm |= BT_ATT_PERM_READ_ENCRYPT;
+
+ if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE)
+ perm |= BT_ATT_PERM_WRITE_ENCRYPT;
+
+ if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ)
+ perm |= BT_ATT_PERM_READ_AUTHEN;
+
+ if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
+ perm |= BT_ATT_PERM_WRITE_AUTHEN;
+
return perm;
}
@@ -2047,22 +2185,16 @@ static uint8_t ccc_write_cb(uint16_t value, void *user_data)
return 0;
}
- /*
- * TODO: All of the errors below should fall into the so called
- * "Application Error" range. Since there is no well defined error for
- * these, we return a generic ATT protocol error for now.
- */
-
if (chrc->ntfy_cnt == UINT_MAX) {
/* Maximum number of per-device CCC descriptors configured */
- return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+ return BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
}
/* Don't support undefined CCC values yet */
if (value > 2 ||
(value == 1 && !(chrc->props & BT_GATT_CHRC_PROP_NOTIFY)) ||
(value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE)))
- return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+ return BT_ERROR_CCC_IMPROPERLY_CONFIGURED;
/*
* Always call StartNotify for an incoming enable and ignore the return
@@ -2071,7 +2203,7 @@ static uint8_t ccc_write_cb(uint16_t value, void *user_data)
if (g_dbus_proxy_method_call(chrc->proxy,
"StartNotify", NULL, NULL,
NULL, NULL) == FALSE)
- return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+ return BT_ATT_ERROR_UNLIKELY;
__sync_fetch_and_add(&chrc->ntfy_cnt, 1);
@@ -2142,12 +2274,11 @@ static void property_changed_cb(GDBusProxy *proxy, const char *name,
enable = get_ccc_notify_indicate(chrc->ccc);
if (enable) {
-
unicast_addr = get_ccc_unicast_address(chrc->ccc);
if (unicast_addr && bacmp(unicast_addr, BDADDR_ANY)) {
send_unicast_notification_indication_to_device(proxy,
- chrc->service->database,
+ chrc->service->app->database,
gatt_db_attribute_get_handle(chrc->attrib),
value, len,
gatt_db_attribute_get_handle(chrc->ccc),
@@ -2155,13 +2286,14 @@ static void property_changed_cb(GDBusProxy *proxy, const char *name,
unicast_addr);
/* reset the unicast address */
set_ccc_unicast_address(chrc->ccc, NULL);
- } else
+ } else {
send_notification_indication_to_devices(proxy,
- chrc->service->database,
+ chrc->service->app->database,
gatt_db_attribute_get_handle(chrc->attrib),
value, len,
gatt_db_attribute_get_handle(chrc->ccc),
chrc->props & BT_GATT_CHRC_PROP_INDICATE);
+ }
set_ccc_notify_indicate(chrc->ccc, FALSE);
}
@@ -2186,7 +2318,7 @@ static void property_changed_cb(GDBusProxy *proxy, const char *name,
len = MIN(BT_ATT_MAX_VALUE_LEN, len);
value = len ? value : NULL;
- send_notification_to_devices(chrc->service->database,
+ send_notification_to_devices(chrc->service->app->database,
gatt_db_attribute_get_handle(chrc->attrib),
value, len,
gatt_db_attribute_get_handle(chrc->ccc),
@@ -2201,7 +2333,7 @@ static bool database_add_ccc(struct external_service *service,
!(chrc->props & BT_GATT_CHRC_PROP_INDICATE))
return true;
- chrc->ccc = service_add_ccc(service->attrib, service->database,
+ chrc->ccc = service_add_ccc(service->attrib, service->app->database,
ccc_write_cb, chrc, NULL);
if (!chrc->ccc) {
error("Failed to create CCC entry for characteristic");
@@ -2309,13 +2441,10 @@ static bool database_add_desc(struct external_service *service,
return false;
}
- /*
- * TODO: Set permissions based on a D-Bus property of the external
- * descriptor.
- */
desc->attrib = gatt_db_service_add_descriptor(service->attrib, &uuid,
- BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
- desc_read_cb, desc_write_cb, desc);
+ desc->perm,
+ desc_read_cb,
+ desc_write_cb, desc);
if (!desc->attrib) {
error("Failed to create descriptor entry in database");
return false;
@@ -2345,6 +2474,38 @@ static void chrc_read_cb(struct gatt_db_attribute *attrib,
#endif
}
+#ifndef __TIZEN_PATCH__
+static void write_without_response_setup_cb(DBusMessageIter *iter,
+ void *user_data)
+{
+ struct iovec *iov = user_data;
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+ &iov->iov_base, iov->iov_len);
+ dbus_message_iter_close_container(iter, &array);
+}
+
+static void send_write_without_response(struct gatt_db_attribute *attrib,
+ GDBusProxy *proxy, unsigned int id,
+ const uint8_t *value, size_t len)
+{
+ struct iovec iov;
+ uint8_t ecode = 0;
+
+ iov.iov_base = (uint8_t *) value;
+ iov.iov_len = len;
+
+ if (!g_dbus_proxy_method_call(proxy, "WriteValue",
+ write_without_response_setup_cb,
+ NULL, &iov, NULL))
+ ecode = BT_ATT_ERROR_UNLIKELY;
+
+ gatt_db_attribute_write_result(attrib, id, ecode);
+}
+#endif
+
static void chrc_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
@@ -2359,8 +2520,24 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib,
}
#ifdef __TIZEN_PATCH__
+ if ((!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) &&
+ opcode == BT_ATT_OP_WRITE_CMD) ||
+ (!(chrc->props & BT_GATT_CHRC_PROP_WRITE) &&
+ opcode == BT_ATT_OP_WRITE_REQ)) {
+ uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
+ error("Property and opcode is not matched");
+ gatt_db_attribute_write_result(attrib, id, ecode);
+ return;
+ }
+
send_write(attrib, att, chrc->proxy, chrc->pending_writes, id, value, len);
#else
+ if (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
+ send_write_without_response(attrib, chrc->proxy, id, value,
+ len);
+ return;
+ }
+
send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len);
#endif
}
@@ -2427,16 +2604,13 @@ static bool database_add_chrc(struct external_service *service,
return false;
/* Handle the descriptors that belong to this characteristic. */
- entry = queue_get_entries(service->descs);
- while (entry) {
+ for (entry = queue_get_entries(service->descs); entry;
+ entry = entry->next) {
struct external_desc *desc = entry->data;
- if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path)) {
-#ifdef __TIZEN_PATCH__
- entry = entry->next;
-#endif
+ if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path))
continue;
- }
+
#ifdef __TIZEN_PATCH__
/* Check if Application wants to add CCC and use existing
* implemenation to add CCC descriptors */
@@ -2459,7 +2633,6 @@ static bool database_add_chrc(struct external_service *service,
return false;
}
#endif
- entry = entry->next;
}
return true;
@@ -2472,7 +2645,7 @@ static bool match_desc_unhandled(const void *a, const void *b)
return !desc->handled;
}
-static bool create_service_entry(struct external_service *service)
+static bool database_add_service(struct external_service *service)
{
bt_uuid_t uuid;
bool primary;
@@ -2488,7 +2661,7 @@ static bool create_service_entry(struct external_service *service)
return false;
}
- service->attrib = gatt_db_add_service(service->database->db, &uuid,
+ service->attrib = gatt_db_add_service(service->app->database->db, &uuid,
primary, service->attr_cnt);
if (!service->attrib)
return false;
@@ -2516,105 +2689,114 @@ static bool create_service_entry(struct external_service *service)
return true;
fail:
- gatt_db_remove_service(service->database->db, service->attrib);
+ gatt_db_remove_service(service->app->database->db, service->attrib);
service->attrib = NULL;
return false;
}
+static bool database_add_app(struct gatt_app *app)
+{
+ const struct queue_entry *entry;
+
+ if (queue_isempty(app->services))
+ return false;
+
+ entry = queue_get_entries(app->services);
+ while (entry) {
+ if (!database_add_service(entry->data)) {
+ error("Failed to add service");
+ return false;
+ }
+
+ entry = entry->next;
+ }
+
+ return true;
+}
+
static void client_ready_cb(GDBusClient *client, void *user_data)
{
- struct external_service *service = user_data;
+ struct gatt_app *app = user_data;
DBusMessage *reply;
bool fail = false;
- if (!service->proxy || service->failed) {
+ if (!app->services || app->failed) {
error("No valid external GATT objects found");
fail = true;
- reply = btd_error_failed(service->reg,
+ reply = btd_error_failed(app->reg,
"No valid service object found");
goto reply;
}
- if (!create_service_entry(service)) {
+ if (!database_add_app(app)) {
error("Failed to create GATT service entry in local database");
fail = true;
- reply = btd_error_failed(service->reg,
+ reply = btd_error_failed(app->reg,
"Failed to create entry in database");
goto reply;
}
- DBG("GATT service registered: %s", service->path);
+ DBG("GATT application registered: %s:%s", app->owner, app->path);
- reply = dbus_message_new_method_return(service->reg);
+ reply = dbus_message_new_method_return(app->reg);
reply:
g_dbus_send_message(btd_get_dbus_connection(), reply);
- dbus_message_unref(service->reg);
- service->reg = NULL;
+ dbus_message_unref(app->reg);
+ app->reg = NULL;
if (fail)
- service_remove(service);
+ remove_app(app);
}
-static struct external_service *service_create(DBusConnection *conn,
- DBusMessage *msg, const char *path)
+static struct gatt_app *create_app(DBusConnection *conn, DBusMessage *msg,
+ const char *path)
{
- struct external_service *service;
+ struct gatt_app *app;
const char *sender = dbus_message_get_sender(msg);
if (!path || !g_str_has_prefix(path, "/"))
return NULL;
- service = new0(struct external_service, 1);
- if (!service)
- return NULL;
-
- service->client = g_dbus_client_new_full(conn, sender, path, path);
- if (!service->client)
- goto fail;
+ app = new0(struct gatt_app, 1);
- service->owner = g_strdup(sender);
- if (!service->owner)
+ app->client = g_dbus_client_new_full(conn, sender, path, path);
+ if (!app->client)
goto fail;
- service->path = g_strdup(path);
- if (!service->path)
+ app->owner = g_strdup(sender);
+ if (!app->owner)
goto fail;
- service->chrcs = queue_new();
- if (!service->chrcs)
+ app->path = g_strdup(path);
+ if (!app->path)
goto fail;
- service->descs = queue_new();
- if (!service->descs)
- goto fail;
+ app->services = queue_new();
+ app->reg = dbus_message_ref(msg);
- service->reg = dbus_message_ref(msg);
+ g_dbus_client_set_disconnect_watch(app->client, client_disconnect_cb,
+ app);
+ g_dbus_client_set_proxy_handlers(app->client, proxy_added_cb,
+ proxy_removed_cb, NULL, app);
+ g_dbus_client_set_ready_watch(app->client, client_ready_cb, app);
- g_dbus_client_set_disconnect_watch(service->client,
- client_disconnect_cb, service);
- g_dbus_client_set_proxy_handlers(service->client, proxy_added_cb,
- proxy_removed_cb, NULL,
- service);
- g_dbus_client_set_ready_watch(service->client, client_ready_cb,
- service);
-
- return service;
+ return app;
fail:
- service_free(service);
+ app_free(app);
return NULL;
}
-static DBusMessage *manager_register_service(DBusConnection *conn,
+static DBusMessage *manager_register_app(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct btd_gatt_database *database = user_data;
const char *sender = dbus_message_get_sender(msg);
DBusMessageIter args;
const char *path;
- struct external_service *service;
+ struct gatt_app *app;
struct svc_match_data match_data;
if (!dbus_message_iter_init(msg, &args))
@@ -2628,33 +2810,33 @@ static DBusMessage *manager_register_service(DBusConnection *conn,
match_data.path = path;
match_data.sender = sender;
- if (queue_find(database->services, match_service, &match_data))
+ if (queue_find(database->apps, match_app, &match_data))
return btd_error_already_exists(msg);
dbus_message_iter_next(&args);
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
return btd_error_invalid_args(msg);
- service = service_create(conn, msg, path);
- if (!service)
- return btd_error_failed(msg, "Failed to register service");
+ app = create_app(conn, msg, path);
+ if (!app)
+ return btd_error_failed(msg, "Failed to register application");
- DBG("Registering service - path: %s", path);
+ DBG("Registering application: %s:%s", sender, path);
- service->database = database;
- queue_push_tail(database->services, service);
+ app->database = database;
+ queue_push_tail(database->apps, app);
return NULL;
}
-static DBusMessage *manager_unregister_service(DBusConnection *conn,
+static DBusMessage *manager_unregister_app(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct btd_gatt_database *database = user_data;
const char *sender = dbus_message_get_sender(msg);
const char *path;
DBusMessageIter args;
- struct external_service *service;
+ struct gatt_app *app;
struct svc_match_data match_data;
if (!dbus_message_iter_init(msg, &args))
@@ -2668,12 +2850,11 @@ static DBusMessage *manager_unregister_service(DBusConnection *conn,
match_data.path = path;
match_data.sender = sender;
- service = queue_remove_if(database->services, match_service,
- &match_data);
- if (!service)
+ app = queue_remove_if(database->apps, match_app, &match_data);
+ if (!app)
return btd_error_does_not_exist(msg);
- service_free(service);
+ app_free(app);
return dbus_message_new_method_return(msg);
}
@@ -2691,46 +2872,60 @@ static void profile_exited(DBusConnection *conn, void *user_data)
profile_free(profile);
}
+static int profile_device_probe(struct btd_service *service)
+{
+ struct btd_profile *p = btd_service_get_profile(service);
+
+ DBG("%s probed", p->name);
+
+ return 0;
+}
+
+static void profile_device_remove(struct btd_service *service)
+{
+ struct btd_profile *p = btd_service_get_profile(service);
+
+ DBG("%s removed", p->name);
+}
+
static int profile_add(struct external_profile *profile, const char *uuid)
{
struct btd_profile *p;
p = new0(struct btd_profile, 1);
- if (!p)
- goto fail;
+
/* Assign directly to avoid having extra fields */
p->name = (const void *) g_strdup_printf("%s%s/%s", profile->owner,
profile->path, uuid);
- if (!p->name)
- goto fail;
+ if (!p->name) {
+ free(p);
+ return -ENOMEM;
+ }
p->remote_uuid = (const void *) g_strdup(uuid);
- if (!p->remote_uuid)
- goto fail;
+ if (!p->remote_uuid) {
+ g_free((void *) p->name);
+ free(p);
+ return -ENOMEM;
+ }
+ p->device_probe = profile_device_probe;
+ p->device_remove = profile_device_remove;
p->auto_connect = true;
+ p->external = true;
queue_push_tail(profile->profiles, p);
DBG("Added \"%s\"", p->name);
return 0;
-fail:
- error("Fail to add profile");
-
- if (p) {
- g_free((char *)p->name);
- g_free((char *)p->remote_uuid);
- free(p);
- }
-
- return -ENOMEM;
}
static void add_profile(void *data, void *user_data)
{
struct btd_adapter *adapter = user_data;
+ btd_profile_register(data);
adapter_add_profile(adapter, data);
}
@@ -2746,8 +2941,6 @@ static int profile_create(DBusConnection *conn,
return -EINVAL;
profile = new0(struct external_profile, 1);
- if (!profile)
- return -ENOMEM;
profile->owner = g_strdup(sender);
if (!profile->owner)
@@ -2758,9 +2951,6 @@ static int profile_create(DBusConnection *conn,
goto fail;
profile->profiles = queue_new();
- if (!profile->profiles)
- goto fail;
-
profile->database = database;
profile->id = g_dbus_add_disconnect_watch(conn, sender, profile_exited,
profile, NULL);
@@ -2868,12 +3058,13 @@ static DBusMessage *manager_unregister_profile(DBusConnection *conn,
static const GDBusMethodTable manager_methods[] = {
#ifdef __TIZEN_PATCH__
- { GDBUS_ASYNC_METHOD("RegisterService",
- GDBUS_ARGS({ "service", "o" }, { "options", "a{sv}" }),
- NULL, manager_register_service) },
- { GDBUS_ASYNC_METHOD("UnregisterService",
- GDBUS_ARGS({ "service", "o" }),
- NULL, manager_unregister_service) },
+ { GDBUS_ASYNC_METHOD("RegisterApplication",
+ GDBUS_ARGS({ "application", "o" },
+ { "options", "a{sv}" }), NULL,
+ manager_register_app) },
+ { GDBUS_ASYNC_METHOD("UnregisterApplication",
+ GDBUS_ARGS({ "application", "o" }),
+ NULL, manager_unregister_app) },
{ GDBUS_ASYNC_METHOD("RegisterProfile",
GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" },
{ "options", "a{sv}" }), NULL,
@@ -2883,12 +3074,13 @@ static const GDBusMethodTable manager_methods[] = {
NULL, manager_unregister_profile) },
{ }
#else
- { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterService",
- GDBUS_ARGS({ "service", "o" }, { "options", "a{sv}" }),
- NULL, manager_register_service) },
- { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterService",
- GDBUS_ARGS({ "service", "o" }),
- NULL, manager_unregister_service) },
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterApplication",
+ GDBUS_ARGS({ "application", "o" },
+ { "options", "a{sv}" }), NULL,
+ manager_register_app) },
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterApplication",
+ GDBUS_ARGS({ "application", "o" }),
+ NULL, manager_unregister_app) },
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterProfile",
GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" },
{ "options", "a{sv}" }), NULL,
@@ -2910,29 +3102,12 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
return NULL;
database = new0(struct btd_gatt_database, 1);
- if (!database)
- return NULL;
-
database->adapter = btd_adapter_ref(adapter);
database->db = gatt_db_new();
- if (!database->db)
- goto fail;
-
database->device_states = queue_new();
- if (!database->device_states)
- goto fail;
-
- database->services = queue_new();
- if (!database->services)
- goto fail;
-
+ database->apps = queue_new();
database->profiles = queue_new();
- if (!database->profiles)
- goto fail;
-
database->ccc_callbacks = queue_new();
- if (!database->ccc_callbacks)
- goto fail;
database->db_id = gatt_db_register(database->db, gatt_db_service_added,
gatt_db_service_removed,
diff --git a/src/log.c b/src/log.c
index 71372581..6cae4188 100644
--- a/src/log.c
+++ b/src/log.c
@@ -26,21 +26,125 @@
#endif
#include <stdio.h>
-#include <stdarg.h>
+#include <errno.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
#include <glib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+
+#include "src/shared/util.h"
#include "log.h"
-void info(const char *format, ...)
+#define LOG_IDENT "bluetoothd"
+#define LOG_IDENT_LEN sizeof(LOG_IDENT)
+
+struct log_hdr {
+ uint16_t opcode;
+ uint16_t index;
+ uint16_t len;
+ uint8_t priority;
+ uint8_t ident_len;
+} __attribute__((packed));
+
+static int logging_fd = -1;
+
+static void logging_open(void)
+{
+ struct sockaddr_hci addr;
+ int fd;
+
+ if (logging_fd >= 0)
+ return;
+
+ fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0)
+ return;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = HCI_DEV_NONE;
+ addr.hci_channel = HCI_CHANNEL_LOGGING;
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(fd);
+ return;
+ }
+
+ logging_fd = fd;
+}
+
+static void logging_close(void)
+{
+ if (logging_fd >= 0) {
+ close(logging_fd);
+ logging_fd = -1;
+ }
+}
+
+static void logging_log(uint16_t index, int priority,
+ const char *format, va_list ap)
+{
+ struct log_hdr hdr;
+ struct msghdr msg;
+ struct iovec iov[3];
+ uint16_t len;
+ char *str;
+
+ if (vasprintf(&str, format, ap) < 0)
+ return;
+
+ len = strlen(str) + 1;
+
+ hdr.opcode = cpu_to_le16(0x0000);
+ hdr.index = cpu_to_le16(index);
+ hdr.len = cpu_to_le16(2 + LOG_IDENT_LEN + len);
+ hdr.priority = priority;
+ hdr.ident_len = LOG_IDENT_LEN;
+
+ iov[0].iov_base = &hdr;
+ iov[0].iov_len = sizeof(hdr);
+
+ iov[1].iov_base = LOG_IDENT;
+ iov[1].iov_len = LOG_IDENT_LEN;
+
+ iov[2].iov_base = str;
+ iov[2].iov_len = len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 3;
+
+ if (sendmsg(logging_fd, &msg, 0) < 0) {
+ if (errno != ENODEV) {
+ close(logging_fd);
+ logging_fd = -1;
+ }
+ }
+
+ free(str);
+}
+
+void error(const char *format, ...)
{
va_list ap;
va_start(ap, format);
+ vsyslog(LOG_ERR, format, ap);
+ va_end(ap);
- vsyslog(LOG_INFO, format, ap);
+ if (logging_fd < 0)
+ return;
+ va_start(ap, format);
+ logging_log(HCI_DEV_NONE, LOG_ERR, format, ap);
va_end(ap);
}
@@ -49,31 +153,110 @@ void warn(const char *format, ...)
va_list ap;
va_start(ap, format);
-
vsyslog(LOG_WARNING, format, ap);
+ va_end(ap);
+ if (logging_fd < 0)
+ return;
+
+ va_start(ap, format);
+ logging_log(HCI_DEV_NONE, LOG_WARNING, format, ap);
va_end(ap);
}
-void error(const char *format, ...)
+void info(const char *format, ...)
{
va_list ap;
va_start(ap, format);
+ vsyslog(LOG_INFO, format, ap);
+ va_end(ap);
+ if (logging_fd < 0)
+ return;
+
+ va_start(ap, format);
+ logging_log(HCI_DEV_NONE, LOG_INFO, format, ap);
+ va_end(ap);
+}
+
+void btd_log(uint16_t index, int priority, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vsyslog(priority, format, ap);
+ va_end(ap);
+
+ if (logging_fd < 0)
+ return;
+
+ va_start(ap, format);
+ logging_log(index, priority, format, ap);
+ va_end(ap);
+}
+
+void btd_error(uint16_t index, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
vsyslog(LOG_ERR, format, ap);
+ va_end(ap);
+
+ if (logging_fd < 0)
+ return;
+ va_start(ap, format);
+ logging_log(index, LOG_ERR, format, ap);
va_end(ap);
}
-void btd_debug(const char *format, ...)
+void btd_warn(uint16_t index, const char *format, ...)
{
va_list ap;
va_start(ap, format);
+ vsyslog(LOG_WARNING, format, ap);
+ va_end(ap);
+ if (logging_fd < 0)
+ return;
+
+ va_start(ap, format);
+ logging_log(index, LOG_WARNING, format, ap);
+ va_end(ap);
+}
+
+void btd_info(uint16_t index, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vsyslog(LOG_INFO, format, ap);
+ va_end(ap);
+
+ if (logging_fd < 0)
+ return;
+
+ va_start(ap, format);
+ logging_log(index, LOG_INFO, format, ap);
+ va_end(ap);
+}
+
+void btd_debug(uint16_t index, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
vsyslog(LOG_DEBUG, format, ap);
+ va_end(ap);
+ if (logging_fd < 0)
+ return;
+
+ va_start(ap, format);
+ logging_log(index, LOG_DEBUG, format, ap);
va_end(ap);
}
@@ -124,18 +307,13 @@ void __hci_attach_log_init(void)
{
int option = LOG_NDELAY | LOG_PID;
- /* Fix : RESOURCE_LEAK */
- char *str = g_strdup("*");
-
- enabled = g_strsplit_set(str, ":, ", 0);
+ enabled = g_strsplit_set(g_strdup("*"), ":, ", 0);
__btd_enable_debug(__start___debug, __stop___debug);
openlog("hciattach", option, LOG_DAEMON);
syslog(LOG_INFO, "hciattach daemon for debugging");
-
- g_free(str);
}
#endif
@@ -149,17 +327,21 @@ void __btd_log_init(const char *debug, int detach)
__btd_enable_debug(__start___debug, __stop___debug);
+ logging_open();
+
if (!detach)
option |= LOG_PERROR;
- openlog("bluetoothd", option, LOG_DAEMON);
+ openlog(LOG_IDENT, option, LOG_DAEMON);
- syslog(LOG_INFO, "Bluetooth daemon %s", VERSION);
+ info("Bluetooth daemon %s", VERSION);
}
void __btd_log_cleanup(void)
{
closelog();
+ logging_close();
+
g_strfreev(enabled);
}
diff --git a/src/log.h b/src/log.h
index a24862a9..f07821c7 100644
--- a/src/log.h
+++ b/src/log.h
@@ -21,11 +21,23 @@
*
*/
-void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
+#include <stdint.h>
+
void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void btd_log(uint16_t index, int priority, const char *format, ...)
+ __attribute__((format(printf, 3, 4)));
-void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void btd_error(uint16_t index, const char *format, ...)
+ __attribute__((format(printf, 2, 3)));
+void btd_warn(uint16_t index, const char *format, ...)
+ __attribute__((format(printf, 2, 3)));
+void btd_info(uint16_t index, const char *format, ...)
+ __attribute__((format(printf, 2, 3)));
+void btd_debug(uint16_t index, const char *format, ...)
+ __attribute__((format(printf, 2, 3)));
#ifdef __TIZEN_PATCH__
void __hci_attach_log_init(void );
@@ -52,11 +64,13 @@ void __btd_enable_debug(struct btd_debug_desc *start,
* Simple macro around btd_debug() which also include the function
* name it is called in.
*/
-#define DBG(fmt, arg...) do { \
+#define DBG_IDX(idx, fmt, arg...) do { \
static struct btd_debug_desc __btd_debug_desc \
__attribute__((used, section("__debug"), aligned(8))) = { \
.file = __FILE__, .flags = BTD_DEBUG_FLAG_DEFAULT, \
}; \
if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \
- btd_debug("%s:%s() " fmt, __FILE__, __func__ , ## arg); \
+ btd_debug(idx, "%s:%s() " fmt, __FILE__, __func__ , ## arg); \
} while (0)
+
+#define DBG(fmt, arg...) DBG_IDX(0xffff, fmt, ## arg)
diff --git a/src/main.c b/src/main.c
index 4adf008f..bc6c6138 100644
--- a/src/main.c
+++ b/src/main.c
@@ -48,6 +48,7 @@
#include "gdbus/gdbus.h"
#include "log.h"
+#include "backtrace.h"
#include "lib/uuid.h"
#include "hcid.h"
@@ -59,10 +60,6 @@
#include "profile.h"
#include "systemd.h"
-#ifdef __TIZEN_PATCH__
-#include "gatt.h"
-#endif
-
#define BLUEZ_NAME "org.bluez"
#define DEFAULT_PAIRABLE_TIMEOUT 0 /* disabled */
@@ -371,11 +368,27 @@ static void init_defaults(void)
if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
return;
-
+#ifndef __TIZEN_PATCH__
main_opts.did_source = 0x0002; /* USB */
main_opts.did_vendor = 0x1d6b; /* Linux Foundation */
main_opts.did_product = 0x0246; /* BlueZ */
main_opts.did_version = (major << 8 | minor);
+#endif
+}
+
+static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
+ const gchar *message, gpointer user_data)
+{
+ int priority;
+
+ if (log_level & (G_LOG_LEVEL_ERROR |
+ G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING))
+ priority = 0x03;
+ else
+ priority = 0x06;
+
+ btd_log(0xffff, priority, "GLib: %s", message);
+ btd_backtrace(0xffff);
}
static GMainLoop *event_loop;
@@ -394,7 +407,7 @@ static gboolean quit_eventloop(gpointer user_data)
static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
gpointer user_data)
{
- static unsigned int __terminated = 0;
+ static bool terminated = false;
struct signalfd_siginfo si;
ssize_t result;
int fd;
@@ -411,7 +424,7 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
switch (si.ssi_signo) {
case SIGINT:
case SIGTERM:
- if (__terminated == 0) {
+ if (!terminated) {
info("Terminating");
g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
quit_eventloop, NULL);
@@ -420,7 +433,7 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
adapter_shutdown();
}
- __terminated = 1;
+ terminated = true;
break;
case SIGUSR2:
__btd_toggle_debug();
@@ -603,12 +616,18 @@ int main(int argc, char *argv[])
umask(0077);
+ btd_backtrace_init();
+
event_loop = g_main_loop_new(NULL, FALSE);
signal = setup_signalfd();
__btd_log_init(option_debug, option_detach);
+ g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
+ G_LOG_FLAG_RECURSION,
+ log_handler, NULL);
+
sd_notify(0, "STATUS=Starting up");
main_conf = load_config(CONFIGDIR "/main.conf");
@@ -625,10 +644,6 @@ int main(int argc, char *argv[])
g_dbus_set_flags(gdbus_flags);
-#if 0
- gatt_init();
-#endif
-
if (adapter_init() < 0) {
error("Adapter handling initialization failed");
exit(1);
@@ -638,14 +653,18 @@ int main(int argc, char *argv[])
btd_agent_init();
btd_profile_init();
- if (option_compat == TRUE)
- sdp_flags |= SDP_SERVER_COMPAT;
+ if (main_opts.mode != BT_MODE_LE) {
+ if (option_compat == TRUE)
+ sdp_flags |= SDP_SERVER_COMPAT;
- start_sdp_server(sdp_mtu, sdp_flags);
+ start_sdp_server(sdp_mtu, sdp_flags);
- if (main_opts.did_source > 0)
- register_device_id(main_opts.did_source, main_opts.did_vendor,
- main_opts.did_product, main_opts.did_version);
+ if (main_opts.did_source > 0)
+ register_device_id(main_opts.did_source,
+ main_opts.did_vendor,
+ main_opts.did_product,
+ main_opts.did_version);
+ }
if (mps != MPS_OFF)
register_mps(mps == MPS_MULTIPLE);
@@ -694,13 +713,10 @@ int main(int argc, char *argv[])
adapter_cleanup();
-#if 0
- gatt_cleanup();
-#endif
-
rfkill_exit();
- stop_sdp_server();
+ if (main_opts.mode != BT_MODE_LE)
+ stop_sdp_server();
g_main_loop_unref(event_loop);
diff --git a/src/profile.c b/src/profile.c
index ea8ad990..98101028 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -511,6 +511,7 @@
#endif
+#ifdef __TIZEN_PATCH__
#define PSE_RECORD \
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
<record> \
@@ -552,10 +553,60 @@
<attribute id=\"0x0314\"> \
<uint8 value=\""PBAP_ACCESS"\"/> \
</attribute> \
+ <attribute id=\"0x0200\"> \
+ <uint16 value=\"%u\" name=\"psm\"/> \
+ </attribute> \
+ </record>"
+#else
+#define PSE_RECORD \
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+ <record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x112f\" /> \
+ </sequence> \
+ </attribute> \
+ <attribute id=\"0x0004\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x0100\" /> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0003\" /> \
+ <uint8 value=\"0x%02x\" /> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0008\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ <attribute id=\"0x0005\"> \
+ <sequence> \
+ <uuid value=\"0x1002\" /> \
+ </sequence> \
+ </attribute> \
+ <attribute id=\"0x0009\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x1130\" /> \
+ <uint16 value=\"0x%04x\" /> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" /> \
+ </attribute> \
+ <attribute id=\"0x0314\"> \
+ <uint8 value=\"0x01\"/> \
+ </attribute> \
<attribute id=\"0x0317\"> \
<uint32 value=\"0x00000003\"/> \
</attribute> \
+ <attribute id=\"0x0200\"> \
+ <uint16 value=\"%u\" name=\"psm\"/> \
+ </attribute> \
</record>"
+#endif
#define MAS_RECORD \
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
@@ -604,6 +655,9 @@
<attribute id=\"0x0317\"> \
<uint32 value=\"0x0000007f\"/> \
</attribute> \
+ <attribute id=\"0x0200\"> \
+ <uint16 value=\"%u\" name=\"psm\"/> \
+ </attribute> \
</record>"
#define MNS_RECORD \
@@ -644,12 +698,12 @@
<attribute id=\"0x0100\"> \
<text value=\"%s\"/> \
</attribute> \
- <attribute id=\"0x0200\"> \
- <uint16 value=\"%u\" name=\"psm\"/> \
- </attribute> \
<attribute id=\"0x0317\"> \
<uint32 value=\"0x0000007f\"/> \
</attribute> \
+ <attribute id=\"0x0200\"> \
+ <uint16 value=\"%u\" name=\"psm\"/> \
+ </attribute> \
</record>"
#define SYNC_RECORD \
@@ -965,10 +1019,10 @@ static struct ext_profile *find_ext_profile(const char *owner,
for (l = ext_profiles; l != NULL; l = g_slist_next(l)) {
struct ext_profile *ext = l->data;
- if (!g_str_equal(ext->owner, owner))
+ if (g_strcmp0(ext->owner, owner))
continue;
- if (g_str_equal(ext->path, path))
+ if (!g_strcmp0(ext->path, path))
return ext;
}
@@ -1032,8 +1086,13 @@ static gboolean ext_io_disconnected(GIOChannel *io, GIOCondition cond,
DBG("%s disconnected from %s", ext->name, addr);
drop:
- if (conn->service)
- btd_service_disconnecting_complete(conn->service, 0);
+ if (conn->service) {
+ if (btd_service_get_state(conn->service) ==
+ BTD_SERVICE_STATE_CONNECTING)
+ btd_service_connecting_complete(conn->service, -EIO);
+ else
+ btd_service_disconnecting_complete(conn->service, 0);
+ }
ext->conns = g_slist_remove(ext->conns, conn);
ext_io_destroy(conn);
@@ -1047,8 +1106,6 @@ static void new_conn_reply(DBusPendingCall *call, void *user_data)
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusError err;
- DBG("+");
-
dbus_error_init(&err);
dbus_set_error_from_message(&err, reply);
@@ -1185,7 +1242,7 @@ static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn)
const sdp_record_t *rec;
const char *path;
int fd;
- DBG("Sending New Connection owner %s path %s", ext->owner, ext->path);
+
msg = dbus_message_new_method_call(ext->owner, ext->path,
"org.bluez.Profile1",
"NewConnection");
@@ -1300,6 +1357,7 @@ static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
conn->io_id = g_io_add_watch(io, cond, ext_io_disconnected,
conn);
}
+
#ifdef TIZEN_BT_HID_DEVICE_ENABLE
if (g_strcmp0(ext->uuid, HID_UUID) == 0 && ext->local_connect == TRUE) {
GSList *l = NULL;
@@ -1325,8 +1383,11 @@ static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
}
}
#endif
- if (send_new_connection(ext, conn))
- return;
+
+ if (conn->service && service_accept(conn->service) == 0) {
+ if (send_new_connection(ext, conn))
+ return;
+ }
drop:
if (conn->service)
@@ -2206,15 +2267,29 @@ static char *get_pce_record(struct ext_profile *ext, struct ext_io *l2cap,
static char *get_pse_record(struct ext_profile *ext, struct ext_io *l2cap,
struct ext_io *rfcomm)
{
- return g_strdup_printf(PSE_RECORD, rfcomm->chan, ext->version,
- ext->name);
+ uint16_t psm = 0;
+ uint8_t chan = 0;
+
+ if (l2cap)
+ psm = l2cap->psm;
+ if (rfcomm)
+ chan = rfcomm->chan;
+
+ return g_strdup_printf(PSE_RECORD, chan, ext->version, ext->name, psm);
}
static char *get_mas_record(struct ext_profile *ext, struct ext_io *l2cap,
struct ext_io *rfcomm)
{
- return g_strdup_printf(MAS_RECORD, rfcomm->chan, ext->version,
- ext->name);
+ uint16_t psm = 0;
+ uint8_t chan = 0;
+
+ if (l2cap)
+ psm = l2cap->psm;
+ if (rfcomm)
+ chan = rfcomm->chan;
+
+ return g_strdup_printf(MAS_RECORD, chan, ext->version, ext->name, psm);
}
static char *get_mns_record(struct ext_profile *ext, struct ext_io *l2cap,
@@ -2237,6 +2312,7 @@ static char *get_sync_record(struct ext_profile *ext, struct ext_io *l2cap,
return g_strdup_printf(SYNC_RECORD, rfcomm->chan, ext->version,
ext->name);
}
+
#ifdef TIZEN_BT_HID_DEVICE_ENABLE
static char *get_hid_device_record(struct ext_profile *ext, struct ext_io *l2cap,
struct ext_io *rfcomm)
@@ -2244,6 +2320,7 @@ static char *get_hid_device_record(struct ext_profile *ext, struct ext_io *l2cap
return g_strdup(HID_DEVICE_RECORD);
}
#endif
+
static char *get_opp_record(struct ext_profile *ext, struct ext_io *l2cap,
struct ext_io *rfcomm)
{
@@ -2437,6 +2514,8 @@ static struct default_settings {
.uuid = OBEX_PSE_UUID,
.name = "Phone Book Access",
.channel = PBAP_DEFAULT_CHANNEL,
+ .psm = BTD_PROFILE_PSM_AUTO,
+ .mode = BT_IO_MODE_ERTM,
.authorize = true,
.get_record = get_pse_record,
.version = 0x0101,
@@ -2451,6 +2530,8 @@ static struct default_settings {
.uuid = OBEX_MAS_UUID,
.name = "Message Access",
.channel = MAS_DEFAULT_CHANNEL,
+ .psm = BTD_PROFILE_PSM_AUTO,
+ .mode = BT_IO_MODE_ERTM,
.authorize = true,
.get_record = get_mas_record,
.version = 0x0100
@@ -2573,10 +2654,32 @@ static int parse_ext_opt(struct ext_profile *ext, const char *key,
return -EINVAL;
dbus_message_iter_get_basic(value, &b);
+#ifndef __TIZEN_PATCH__
if (b)
ext->sec_level = BT_IO_SEC_MEDIUM;
else
ext->sec_level = BT_IO_SEC_LOW;
+#else
+#ifdef TIZEN_BT_IO_CAPA_NO_INPUT_OUTPUT
+ /*
+ * NoInputOut device should have another authentication method.
+ * So turn off force authentication setting for that device.
+ */
+ if (b)
+ ext->sec_level = BT_IO_SEC_MEDIUM;
+ else
+ ext->sec_level = BT_IO_SEC_LOW;
+#else
+ if (!strcasecmp(ext->uuid, WEARABLE_OLD_SAP_UUID) ||
+ !strcasecmp(ext->uuid, WEARABLE_NEW_SAP_UUID)) {
+ DBG("Set SAP UUID's sec_level to HIGH");
+ ext->sec_level = BT_IO_SEC_HIGH;
+ } else if (b)
+ ext->sec_level = BT_IO_SEC_MEDIUM;
+ else
+ ext->sec_level = BT_IO_SEC_LOW;
+#endif
+#endif
} else if (strcasecmp(key, "RequireAuthorization") == 0) {
if (type != DBUS_TYPE_BOOLEAN)
return -EINVAL;
@@ -2797,6 +2900,7 @@ static struct ext_profile *create_ext(const char *owner, const char *path,
p->name = ext->name;
p->local_uuid = ext->service ? ext->service : ext->uuid;
p->remote_uuid = ext->remote_uuid;
+ p->external = true;
if (ext->enable_server) {
p->adapter_probe = ext_adapter_probe;
@@ -3074,11 +3178,22 @@ void btd_profile_cleanup(void)
g_slist_free_full(ext->conns, ext_io_destroy);
ext->conns = NULL;
+#ifdef __TIZEN_PATCH__
+ if (ext->destination == NULL) {
+ msg = dbus_message_new_method_call(ext->owner,
+ ext->path,
+ "org.bluez.Profile1",
+ "Release");
+ if (msg)
+ g_dbus_send_message(conn, msg);
+ }
+#else
msg = dbus_message_new_method_call(ext->owner, ext->path,
"org.bluez.Profile1",
"Release");
if (msg)
g_dbus_send_message(conn, msg);
+#endif
g_dbus_remove_watch(conn, ext->id);
remove_ext(ext);
diff --git a/src/profile.h b/src/profile.h
index cd3eb2cd..938d67c7 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -35,6 +35,7 @@ struct btd_profile {
const char *remote_uuid;
bool auto_connect;
+ bool external;
int (*device_probe) (struct btd_service *service);
void (*device_remove) (struct btd_service *service);
diff --git a/src/sdp-xml.c b/src/sdp-xml.c
index d8eb02fe..8a84caf7 100644
--- a/src/sdp-xml.c
+++ b/src/sdp-xml.c
@@ -530,6 +530,7 @@ static void element_end(GMarkupParseContext *context,
{
struct context_data *ctx_data = user_data;
struct sdp_xml_data *elem;
+
#ifdef __TIZEN_PATCH__
if (element_name == NULL)
return;
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index e6b611ae..c863508d 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -46,8 +46,7 @@
#include "sdpd.h"
static guint l2cap_id = 0, unix_id = 0;
-
-static int l2cap_sock, unix_sock;
+static int l2cap_sock = -1, unix_sock = -1;
/*
* SDP server initialization on startup includes creating the
diff --git a/src/service.c b/src/service.c
index 250f56e8..6d81cd1d 100644
--- a/src/service.c
+++ b/src/service.c
@@ -27,7 +27,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdbool.h>
@@ -41,6 +40,7 @@
#include "lib/sdp.h"
#include "log.h"
+#include "backtrace.h"
#include "adapter.h"
#include "device.h"
@@ -92,8 +92,8 @@ static void change_state(struct btd_service *service, btd_service_state_t state,
if (state == old)
return;
- assert(service->device != NULL);
- assert(service->profile != NULL);
+ btd_assert(service->device != NULL);
+ btd_assert(service->profile != NULL);
service->state = state;
service->err = err;
@@ -155,7 +155,7 @@ int service_probe(struct btd_service *service)
char addr[18];
int err;
- assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
+ btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
err = service->profile->device_probe(service);
if (err == 0) {
@@ -171,6 +171,10 @@ int service_probe(struct btd_service *service)
void service_remove(struct btd_service *service)
{
+#ifdef __TIZEN_PATCH__
+ if (service->profile == NULL)
+ return;
+#endif
change_state(service, BTD_SERVICE_STATE_DISCONNECTED, -ECONNABORTED);
change_state(service, BTD_SERVICE_STATE_UNAVAILABLE, 0);
service->profile->device_remove(service);
@@ -184,17 +188,33 @@ int service_accept(struct btd_service *service)
char addr[18];
int err;
- if (!service->profile->accept)
+ switch (service->state) {
+ case BTD_SERVICE_STATE_UNAVAILABLE:
+ return -EINVAL;
+ case BTD_SERVICE_STATE_DISCONNECTED:
+ break;
+ case BTD_SERVICE_STATE_CONNECTING:
+ case BTD_SERVICE_STATE_CONNECTED:
return 0;
+ case BTD_SERVICE_STATE_DISCONNECTING:
+ return -EBUSY;
+ }
+
+ if (!service->profile->accept)
+ goto done;
err = service->profile->accept(service);
if (!err)
- return 0;
+ goto done;
ba2str(device_get_address(service->device), addr);
error("%s profile accept failed for %s", service->profile->name, addr);
return err;
+
+done:
+ change_state(service, BTD_SERVICE_STATE_CONNECTING, 0);
+ return 0;
}
int btd_service_connect(struct btd_service *service)
@@ -215,6 +235,7 @@ int btd_service_connect(struct btd_service *service)
case BTD_SERVICE_STATE_DISCONNECTED:
break;
case BTD_SERVICE_STATE_CONNECTING:
+ return 0;
case BTD_SERVICE_STATE_CONNECTED:
return -EALREADY;
case BTD_SERVICE_STATE_DISCONNECTING:
@@ -286,7 +307,7 @@ struct btd_profile *btd_service_get_profile(const struct btd_service *service)
void btd_service_set_user_data(struct btd_service *service, void *user_data)
{
- assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
+ btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
service->user_data = user_data;
}
@@ -339,9 +360,14 @@ bool btd_service_remove_state_cb(unsigned int id)
void btd_service_connecting_complete(struct btd_service *service, int err)
{
+#ifdef __TIZEN_PATCH__
if (service->state != BTD_SERVICE_STATE_DISCONNECTED &&
- service->state != BTD_SERVICE_STATE_CONNECTING)
+ service->state != BTD_SERVICE_STATE_CONNECTING)
return;
+#else
+ if (service->state != BTD_SERVICE_STATE_CONNECTING)
+ return;
+#endif
if (err == 0)
change_state(service, BTD_SERVICE_STATE_CONNECTED, 0);
diff --git a/src/shared/ad.c b/src/shared/ad.c
new file mode 100644
index 00000000..1bf013d5
--- /dev/null
+++ b/src/shared/ad.c
@@ -0,0 +1,658 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "src/shared/ad.h"
+
+#include "src/eir.h"
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+
+#define MAX_ADV_DATA_LEN 31
+
+struct bt_ad {
+ int ref_count;
+ struct queue *service_uuids;
+ struct queue *manufacturer_data;
+ struct queue *solicit_uuids;
+ struct queue *service_data;
+};
+
+struct bt_ad *bt_ad_new(void)
+{
+ struct bt_ad *ad;
+
+ ad = new0(struct bt_ad, 1);
+ ad->service_uuids = queue_new();
+ ad->manufacturer_data = queue_new();
+ ad->solicit_uuids = queue_new();
+ ad->service_data = queue_new();
+
+ return bt_ad_ref(ad);
+}
+
+struct bt_ad *bt_ad_ref(struct bt_ad *ad)
+{
+ if (!ad)
+ return NULL;
+
+ ad->ref_count++;
+ return ad;
+}
+
+static void uuid_destroy(void *data)
+{
+ struct bt_ad_service_data *uuid_data = data;
+
+ free(uuid_data->data);
+ free(uuid_data);
+}
+
+static bool uuid_data_match(const void *data, const void *elem)
+{
+ const struct bt_ad_service_data *uuid_data = elem;
+ const bt_uuid_t *uuid = data;
+
+ return !bt_uuid_cmp(&uuid_data->uuid, uuid);
+}
+
+static void manuf_destroy(void *data)
+{
+ struct bt_ad_manufacturer_data *manuf = data;
+
+ free(manuf->data);
+ free(manuf);
+}
+
+static bool manuf_match(const void *data, const void *elem)
+{
+ const struct bt_ad_manufacturer_data *manuf = elem;
+ uint16_t manuf_id = PTR_TO_UINT(elem);
+
+ return manuf->manufacturer_id == manuf_id;
+}
+
+void bt_ad_unref(struct bt_ad *ad)
+{
+ if (!ad)
+ return;
+
+ if (__sync_sub_and_fetch(&ad->ref_count, 1))
+ return;
+
+ queue_destroy(ad->service_uuids, free);
+
+ queue_destroy(ad->manufacturer_data, manuf_destroy);
+
+ queue_destroy(ad->solicit_uuids, free);
+
+ queue_destroy(ad->service_data, uuid_destroy);
+
+ free(ad);
+}
+
+static size_t uuid_list_length(struct queue *uuid_queue)
+{
+ bool uuid16_included = false;
+ bool uuid32_included = false;
+ bool uuid128_included = false;
+ size_t length = 0;
+ const struct queue_entry *entry;
+
+ entry = queue_get_entries(uuid_queue);
+
+ while (entry) {
+ bt_uuid_t *uuid = entry->data;
+
+ length += bt_uuid_len(uuid);
+
+ if (uuid->type == BT_UUID16)
+ uuid16_included = true;
+ else if (uuid->type == BT_UUID32)
+ uuid32_included = true;
+ else
+ uuid128_included = true;
+
+ entry = entry->next;
+ }
+
+ if (uuid16_included)
+ length += 2;
+
+ if (uuid32_included)
+ length += 2;
+
+ if (uuid128_included)
+ length += 2;
+
+ return length;
+}
+
+static size_t mfg_data_length(struct queue *manuf_data)
+{
+ size_t length = 0;
+ const struct queue_entry *entry;
+
+ entry = queue_get_entries(manuf_data);
+
+ while (entry) {
+ struct bt_ad_manufacturer_data *data = entry->data;
+
+ length += 2 + sizeof(uint16_t) + data->len;
+
+ entry = entry->next;
+ }
+
+ return length;
+}
+
+static size_t uuid_data_length(struct queue *uuid_data)
+{
+ size_t length = 0;
+ const struct queue_entry *entry;
+
+ entry = queue_get_entries(uuid_data);
+
+ while (entry) {
+ struct bt_ad_service_data *data = entry->data;
+
+ length += 2 + bt_uuid_len(&data->uuid) + data->len;
+
+ entry = entry->next;
+ }
+
+ return length;
+}
+
+static size_t calculate_length(struct bt_ad *ad)
+{
+ size_t length = 0;
+
+ length += uuid_list_length(ad->service_uuids);
+
+ length += uuid_list_length(ad->solicit_uuids);
+
+ length += mfg_data_length(ad->manufacturer_data);
+
+ length += uuid_data_length(ad->service_data);
+
+ return length;
+}
+
+static void serialize_uuids(struct queue *uuids, uint8_t uuid_type,
+ uint8_t ad_type, uint8_t *buf,
+ uint8_t *pos)
+{
+ const struct queue_entry *entry = queue_get_entries(uuids);
+ bool added = false;
+ uint8_t length_pos = 0;
+
+ while (entry) {
+ bt_uuid_t *uuid = entry->data;
+
+ if (uuid->type == uuid_type) {
+ if (!added) {
+ length_pos = (*pos)++;
+ buf[(*pos)++] = ad_type;
+ added = true;
+ }
+
+ if (uuid_type != BT_UUID32)
+ bt_uuid_to_le(uuid, buf + *pos);
+ else
+ bt_put_le32(uuid->value.u32, buf + *pos);
+
+ *pos += bt_uuid_len(uuid);
+ }
+
+ entry = entry->next;
+ }
+
+ if (added)
+ buf[length_pos] = *pos - length_pos - 1;
+}
+
+static void serialize_service_uuids(struct queue *uuids, uint8_t *buf,
+ uint8_t *pos)
+{
+ serialize_uuids(uuids, BT_UUID16, EIR_UUID16_ALL, buf, pos);
+
+ serialize_uuids(uuids, BT_UUID32, EIR_UUID32_ALL, buf, pos);
+
+ serialize_uuids(uuids, BT_UUID128, EIR_UUID128_ALL, buf, pos);
+}
+
+static void serialize_solicit_uuids(struct queue *uuids, uint8_t *buf,
+ uint8_t *pos)
+{
+ serialize_uuids(uuids, BT_UUID16, EIR_SOLICIT16, buf, pos);
+
+ serialize_uuids(uuids, BT_UUID32, EIR_SOLICIT32, buf, pos);
+
+ serialize_uuids(uuids, BT_UUID128, EIR_SOLICIT128, buf, pos);
+}
+
+static void serialize_manuf_data(struct queue *manuf_data, uint8_t *buf,
+ uint8_t *pos)
+{
+ const struct queue_entry *entry = queue_get_entries(manuf_data);
+
+ while (entry) {
+ struct bt_ad_manufacturer_data *data = entry->data;
+
+ buf[(*pos)++] = data->len + 2 + 1;
+
+ buf[(*pos)++] = EIR_MANUFACTURER_DATA;
+
+ bt_put_le16(data->manufacturer_id, buf + (*pos));
+
+ *pos += 2;
+
+ memcpy(buf + *pos, data->data, data->len);
+
+ *pos += data->len;
+
+ entry = entry->next;
+ }
+}
+
+static void serialize_service_data(struct queue *service_data, uint8_t *buf,
+ uint8_t *pos)
+{
+ const struct queue_entry *entry = queue_get_entries(service_data);
+
+ while (entry) {
+ struct bt_ad_service_data *data = entry->data;
+ int uuid_len = bt_uuid_len(&data->uuid);
+
+ buf[(*pos)++] = uuid_len + data->len + 1;
+
+ switch (uuid_len) {
+ case 2:
+ buf[(*pos)++] = EIR_SVC_DATA16;
+ break;
+ case 4:
+ buf[(*pos)++] = EIR_SVC_DATA32;
+ break;
+ case 16:
+ buf[(*pos)++] = EIR_SVC_DATA128;
+ break;
+ }
+
+ if (uuid_len != 4)
+ bt_uuid_to_le(&data->uuid, buf + *pos);
+ else
+ bt_put_le32(data->uuid.value.u32, buf + *pos);
+
+ *pos += uuid_len;
+
+ memcpy(buf + *pos, data->data, data->len);
+
+ *pos += data->len;
+
+ entry = entry->next;
+ }
+}
+
+uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length)
+{
+ uint8_t *adv_data;
+ uint8_t pos = 0;
+
+ if (!ad)
+ return NULL;
+
+ *length = calculate_length(ad);
+
+ if (*length > MAX_ADV_DATA_LEN)
+ return NULL;
+
+ adv_data = malloc0(*length);
+ if (!adv_data)
+ return NULL;
+
+ serialize_service_uuids(ad->service_uuids, adv_data, &pos);
+
+ serialize_solicit_uuids(ad->solicit_uuids, adv_data, &pos);
+
+ serialize_manuf_data(ad->manufacturer_data, adv_data, &pos);
+
+ serialize_service_data(ad->service_data, adv_data, &pos);
+
+ return adv_data;
+}
+
+static bool queue_add_uuid(struct queue *queue, const bt_uuid_t *uuid)
+{
+ bt_uuid_t *new_uuid;
+
+ if (!queue)
+ return false;
+
+ new_uuid = new0(bt_uuid_t, 1);
+
+ *new_uuid = *uuid;
+
+ if (queue_push_tail(queue, new_uuid))
+ return true;
+
+ free(new_uuid);
+
+ return false;
+}
+
+static bool uuid_match(const void *data, const void *elem)
+{
+ const bt_uuid_t *match_uuid = data;
+ const bt_uuid_t *uuid = elem;
+
+ return bt_uuid_cmp(match_uuid, uuid);
+}
+
+static bool queue_remove_uuid(struct queue *queue, bt_uuid_t *uuid)
+{
+ bt_uuid_t *removed;
+
+ if (!queue || !uuid)
+ return false;
+
+ removed = queue_remove_if(queue, uuid_match, uuid);
+
+ if (removed) {
+ free(removed);
+ return true;
+ }
+
+ return false;
+}
+
+bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid)
+{
+ if (!ad)
+ return false;
+
+ return queue_add_uuid(ad->service_uuids, uuid);
+}
+
+bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid)
+{
+ if (!ad)
+ return false;
+
+ return queue_remove_uuid(ad->service_uuids, uuid);
+}
+
+void bt_ad_clear_service_uuid(struct bt_ad *ad)
+{
+ if (!ad)
+ return;
+
+ queue_remove_all(ad->service_uuids, NULL, NULL, free);
+}
+
+static bool manufacturer_id_data_match(const void *data, const void *user_data)
+{
+ const struct bt_ad_manufacturer_data *m = data;
+ uint16_t id = PTR_TO_UINT(user_data);
+
+ return m->manufacturer_id == id;
+}
+
+bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id,
+ void *data, size_t len)
+{
+ struct bt_ad_manufacturer_data *new_data;
+
+ if (!ad)
+ return false;
+
+ if (len > (MAX_ADV_DATA_LEN - 2 - sizeof(uint16_t)))
+ return false;
+
+ new_data = queue_find(ad->manufacturer_data, manufacturer_id_data_match,
+ UINT_TO_PTR(manufacturer_id));
+ if (new_data) {
+ if (new_data->len == len && !memcmp(new_data->data, data, len))
+ return false;
+ new_data->data = realloc(new_data->data, len);
+ memcpy(new_data->data, data, len);
+ new_data->len = len;
+ return true;
+ }
+
+ new_data = new0(struct bt_ad_manufacturer_data, 1);
+ new_data->manufacturer_id = manufacturer_id;
+
+ new_data->data = malloc(len);
+ if (!new_data->data) {
+ free(new_data);
+ return false;
+ }
+
+ memcpy(new_data->data, data, len);
+
+ new_data->len = len;
+
+ if (queue_push_tail(ad->manufacturer_data, new_data))
+ return true;
+
+ manuf_destroy(new_data);
+
+ return false;
+}
+
+static bool manufacturer_data_match(const void *data, const void *user_data)
+{
+ const struct bt_ad_manufacturer_data *m1 = data;
+ const struct bt_ad_manufacturer_data *m2 = user_data;
+
+ if (m1->manufacturer_id != m2->manufacturer_id)
+ return false;
+
+ if (m1->len != m2->len)
+ return false;
+
+ return !memcmp(m1->data, m2->data, m1->len);
+}
+
+bool bt_ad_has_manufacturer_data(struct bt_ad *ad,
+ const struct bt_ad_manufacturer_data *data)
+{
+ if (!ad)
+ return false;
+
+ if (!data)
+ return !queue_isempty(ad->manufacturer_data);
+
+ return queue_find(ad->manufacturer_data, manufacturer_data_match, data);
+}
+
+void bt_ad_foreach_manufacturer_data(struct bt_ad *ad, bt_ad_func_t func,
+ void *user_data)
+{
+ if (!ad)
+ return;
+
+ queue_foreach(ad->manufacturer_data, func, user_data);
+}
+
+bool bt_ad_remove_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id)
+{
+ struct bt_ad_manufacturer_data *data;
+
+ if (!ad)
+ return false;
+
+ data = queue_remove_if(ad->manufacturer_data, manuf_match,
+ UINT_TO_PTR(manufacturer_id));
+
+ if (!data)
+ return false;
+
+ manuf_destroy(data);
+
+ return true;
+}
+
+void bt_ad_clear_manufacturer_data(struct bt_ad *ad)
+{
+ if (!ad)
+ return;
+
+ queue_remove_all(ad->manufacturer_data, NULL, NULL, manuf_destroy);
+}
+
+bool bt_ad_add_solicit_uuid(struct bt_ad *ad, const bt_uuid_t *uuid)
+{
+ if (!ad)
+ return false;
+
+ return queue_add_uuid(ad->solicit_uuids, uuid);
+}
+
+bool bt_ad_remove_solicit_uuid(struct bt_ad *ad, bt_uuid_t *uuid)
+{
+ if (!ad)
+ return false;
+
+ return queue_remove_uuid(ad->solicit_uuids, uuid);
+}
+
+void bt_ad_clear_solicit_uuid(struct bt_ad *ad)
+{
+ if (!ad)
+ return;
+
+ queue_remove_all(ad->solicit_uuids, NULL, NULL, free);
+}
+
+
+static bool service_uuid_match(const void *data, const void *user_data)
+{
+ const struct bt_ad_service_data *s = data;
+ const bt_uuid_t *uuid = user_data;
+
+ return !bt_uuid_cmp(&s->uuid, uuid);
+}
+
+bool bt_ad_add_service_data(struct bt_ad *ad, const bt_uuid_t *uuid, void *data,
+ size_t len)
+{
+ struct bt_ad_service_data *new_data;
+
+ if (!ad)
+ return false;
+
+ if (len > (MAX_ADV_DATA_LEN - 2 - (size_t)bt_uuid_len(uuid)))
+ return false;
+
+ new_data = queue_find(ad->service_data, service_uuid_match, uuid);
+ if (new_data) {
+ if (new_data->len == len && !memcmp(new_data->data, data, len))
+ return false;
+ new_data->data = realloc(new_data->data, len);
+ memcpy(new_data->data, data, len);
+ new_data->len = len;
+ return true;
+ }
+
+ new_data = new0(struct bt_ad_service_data, 1);
+
+ new_data->uuid = *uuid;
+
+ new_data->data = malloc(len);
+ if (!new_data->data) {
+ free(new_data);
+ return false;
+ }
+
+ memcpy(new_data->data, data, len);
+
+ new_data->len = len;
+
+ if (queue_push_tail(ad->service_data, new_data))
+ return true;
+
+ uuid_destroy(new_data);
+
+ return false;
+}
+
+static bool service_data_match(const void *data, const void *user_data)
+{
+ const struct bt_ad_service_data *s1 = data;
+ const struct bt_ad_service_data *s2 = user_data;
+
+ if (bt_uuid_cmp(&s1->uuid, &s2->uuid))
+ return false;
+
+ if (s1->len != s2->len)
+ return false;
+
+ return !memcmp(s1->data, s2->data, s1->len);
+}
+
+bool bt_ad_has_service_data(struct bt_ad *ad,
+ const struct bt_ad_service_data *data)
+{
+ if (!ad)
+ return false;
+
+ if (!data)
+ return !queue_isempty(ad->service_data);
+
+ return queue_find(ad->service_data, service_data_match, data);
+}
+
+void bt_ad_foreach_service_data(struct bt_ad *ad, bt_ad_func_t func,
+ void *user_data)
+{
+ if (!ad)
+ return;
+
+ queue_foreach(ad->service_data, func, user_data);
+}
+
+bool bt_ad_remove_service_data(struct bt_ad *ad, bt_uuid_t *uuid)
+{
+ struct bt_ad_service_data *data;
+
+ if (!ad)
+ return false;
+
+ data = queue_remove_if(ad->service_data, uuid_data_match, uuid);
+
+ if (!data)
+ return false;
+
+ uuid_destroy(data);
+
+ return true;
+}
+
+void bt_ad_clear_service_data(struct bt_ad *ad)
+{
+ if (!ad)
+ return;
+
+ queue_remove_all(ad->service_data, NULL, NULL, uuid_destroy);
+}
diff --git a/src/shared/ad.h b/src/shared/ad.h
new file mode 100644
index 00000000..709563d3
--- /dev/null
+++ b/src/shared/ad.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+
+typedef void (*bt_ad_func_t)(void *data, void *user_data);
+
+struct bt_ad;
+
+struct bt_ad_manufacturer_data {
+ uint16_t manufacturer_id;
+ uint8_t *data;
+ size_t len;
+};
+
+struct bt_ad_service_data {
+ bt_uuid_t uuid;
+ uint8_t *data;
+ size_t len;
+};
+
+struct bt_ad *bt_ad_new(void);
+
+struct bt_ad *bt_ad_ref(struct bt_ad *ad);
+
+void bt_ad_unref(struct bt_ad *ad);
+
+uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length);
+
+bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid);
+
+bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid);
+
+void bt_ad_clear_service_uuid(struct bt_ad *ad);
+
+bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_data,
+ void *data, size_t len);
+
+bool bt_ad_has_manufacturer_data(struct bt_ad *ad,
+ const struct bt_ad_manufacturer_data *data);
+
+void bt_ad_foreach_manufacturer_data(struct bt_ad *ad, bt_ad_func_t func,
+ void *user_data);
+
+bool bt_ad_remove_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id);
+
+void bt_ad_clear_manufacturer_data(struct bt_ad *ad);
+
+bool bt_ad_add_solicit_uuid(struct bt_ad *ad, const bt_uuid_t *uuid);
+
+bool bt_ad_remove_solicit_uuid(struct bt_ad *ad, bt_uuid_t *uuid);
+
+void bt_ad_clear_solicit_uuid(struct bt_ad *ad);
+
+bool bt_ad_add_service_data(struct bt_ad *ad, const bt_uuid_t *uuid, void *data,
+ size_t len);
+
+bool bt_ad_has_service_data(struct bt_ad *ad,
+ const struct bt_ad_service_data *data);
+
+void bt_ad_foreach_service_data(struct bt_ad *ad, bt_ad_func_t func,
+ void *user_data);
+
+bool bt_ad_remove_service_data(struct bt_ad *ad, bt_uuid_t *uuid);
+
+void bt_ad_clear_service_data(struct bt_ad *ad);
diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index aa7f0da0..c3062c00 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -27,6 +27,11 @@
#define __packed __attribute__((packed))
#endif
+#define BT_ATT_SECURITY_AUTO 0
+#define BT_ATT_SECURITY_LOW 1
+#define BT_ATT_SECURITY_MEDIUM 2
+#define BT_ATT_SECURITY_HIGH 3
+
#define BT_ATT_DEFAULT_LE_MTU 23
#define BT_ATT_MAX_LE_MTU 517
#define BT_ATT_MAX_VALUE_LEN 512
@@ -37,8 +42,8 @@
#define BT_ATT_OP_MTU_RSP 0x03
#define BT_ATT_OP_FIND_INFO_REQ 0x04
#define BT_ATT_OP_FIND_INFO_RSP 0x05
-#define BT_ATT_OP_FIND_BY_TYPE_VAL_REQ 0x06
-#define BT_ATT_OP_FIND_BY_TYPE_VAL_RSP 0x07
+#define BT_ATT_OP_FIND_BY_TYPE_REQ 0x06
+#define BT_ATT_OP_FIND_BY_TYPE_RSP 0x07
#define BT_ATT_OP_READ_BY_TYPE_REQ 0x08
#define BT_ATT_OP_READ_BY_TYPE_RSP 0x09
#define BT_ATT_OP_READ_REQ 0x0a
@@ -92,16 +97,32 @@ struct bt_att_pdu_error_rsp {
#define BT_ATT_ERROR_INSUFFICIENT_RESOURCES 0x11
/*
+ * Common Profile and Service Error Code descriptions (see Supplement to the
+ * Bluetooth Core Specification, sections 1.2 and 2). The error codes within
+ * 0xE0-0xFC are reserved for future use. The remaining 3 are defined as the
+ * following:
+ */
+#define BT_ERROR_CCC_IMPROPERLY_CONFIGURED 0xfd
+#define BT_ERROR_ALREADY_IN_PROGRESS 0xfe
+#define BT_ERROR_OUT_OF_RANGE 0xff
+
+/*
* ATT attribute permission bitfield values. Permissions are grouped as
* "Access", "Encryption", "Authentication", and "Authorization". A bitmask of
* permissions is a byte that encodes a combination of these.
*/
-#define BT_ATT_PERM_READ 0x01
-#define BT_ATT_PERM_WRITE 0x02
-#define BT_ATT_PERM_ENCRYPT 0x04
-#define BT_ATT_PERM_AUTHEN 0x08
-#define BT_ATT_PERM_AUTHOR 0x10
-#define BT_ATT_PERM_NONE 0x20
+#define BT_ATT_PERM_READ 0x01
+#define BT_ATT_PERM_WRITE 0x02
+#define BT_ATT_PERM_READ_ENCRYPT 0x04
+#define BT_ATT_PERM_WRITE_ENCRYPT 0x08
+#define BT_ATT_PERM_ENCRYPT (BT_ATT_PERM_READ_ENCRYPT | \
+ BT_ATT_PERM_WRITE_ENCRYPT)
+#define BT_ATT_PERM_READ_AUTHEN 0x10
+#define BT_ATT_PERM_WRITE_AUTHEN 0x20
+#define BT_ATT_PERM_AUTHEN (BT_ATT_PERM_READ_AUTHEN | \
+ BT_ATT_PERM_WRITE_AUTHEN)
+#define BT_ATT_PERM_AUTHOR 0x40
+#define BT_ATT_PERM_NONE 0x80
/* GATT Characteristic Properties Bitfield values */
#define BT_GATT_CHRC_PROP_BROADCAST 0x01
@@ -114,5 +135,13 @@ struct bt_att_pdu_error_rsp {
#define BT_GATT_CHRC_PROP_EXT_PROP 0x80
/* GATT Characteristic Extended Properties Bitfield values */
-#define BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE 0x01
-#define BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX 0x02
+#define BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE 0x01
+#define BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX 0x02
+#define BT_GATT_CHRC_EXT_PROP_ENC_READ 0x04
+#define BT_GATT_CHRC_EXT_PROP_ENC_WRITE 0x08
+#define BT_GATT_CHRC_EXT_PROP_ENC (BT_GATT_CHRC_EXT_PROP_ENC_READ | \
+ BT_GATT_CHRC_EXT_PROP_ENC_WRITE)
+#define BT_GATT_CHRC_EXT_PROP_AUTH_READ 0x10
+#define BT_GATT_CHRC_EXT_PROP_AUTH_WRITE 0x20
+#define BT_GATT_CHRC_EXT_PROP_AUTH (BT_GATT_CHRC_EXT_PROP_AUTH_READ | \
+ BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
diff --git a/src/shared/att.c b/src/shared/att.c
index 422cc2c8..e5cd2239 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -43,16 +43,6 @@
#define ATT_OP_SIGNED_MASK 0x80
#define ATT_TIMEOUT_INTERVAL 30000 /* 30000 ms */
-/*
- * Common Profile and Service Error Code descriptions (see Supplement to the
- * Bluetooth Core Specification, sections 1.2 and 2). The error codes within
- * 0xE0-0xFC are reserved for future use. The remaining 3 are defined as the
- * following:
- */
-#define BT_ERROR_CCC_IMPROPERLY_CONFIGURED 0xfd
-#define BT_ERROR_ALREADY_IN_PROGRESS 0xfe
-#define BT_ERROR_OUT_OF_RANGE 0xff
-
/* Length of signature in write signed packet */
#define BT_ATT_SIGNATURE_LEN 12
@@ -122,8 +112,8 @@ static const struct {
{ BT_ATT_OP_MTU_RSP, ATT_OP_TYPE_RSP },
{ BT_ATT_OP_FIND_INFO_REQ, ATT_OP_TYPE_REQ },
{ BT_ATT_OP_FIND_INFO_RSP, ATT_OP_TYPE_RSP },
- { BT_ATT_OP_FIND_BY_TYPE_VAL_REQ, ATT_OP_TYPE_REQ },
- { BT_ATT_OP_FIND_BY_TYPE_VAL_RSP, ATT_OP_TYPE_RSP },
+ { BT_ATT_OP_FIND_BY_TYPE_REQ, ATT_OP_TYPE_REQ },
+ { BT_ATT_OP_FIND_BY_TYPE_RSP, ATT_OP_TYPE_RSP },
{ BT_ATT_OP_READ_BY_TYPE_REQ, ATT_OP_TYPE_REQ },
{ BT_ATT_OP_READ_BY_TYPE_RSP, ATT_OP_TYPE_RSP },
{ BT_ATT_OP_READ_REQ, ATT_OP_TYPE_REQ },
@@ -166,7 +156,7 @@ static const struct {
} att_req_rsp_mapping_table[] = {
{ BT_ATT_OP_MTU_REQ, BT_ATT_OP_MTU_RSP },
{ BT_ATT_OP_FIND_INFO_REQ, BT_ATT_OP_FIND_INFO_RSP},
- { BT_ATT_OP_FIND_BY_TYPE_VAL_REQ, BT_ATT_OP_FIND_BY_TYPE_VAL_RSP },
+ { BT_ATT_OP_FIND_BY_TYPE_REQ, BT_ATT_OP_FIND_BY_TYPE_RSP },
{ BT_ATT_OP_READ_BY_TYPE_REQ, BT_ATT_OP_READ_BY_TYPE_RSP },
{ BT_ATT_OP_READ_REQ, BT_ATT_OP_READ_RSP },
{ BT_ATT_OP_READ_BLOB_REQ, BT_ATT_OP_READ_BLOB_RSP },
@@ -218,6 +208,10 @@ static void destroy_att_send_op(void *data)
static void cancel_att_send_op(struct att_send_op *op)
{
+#ifdef __TIZEN_PATCH__
+ if (op->callback)
+ op->callback(BT_ATT_OP_ERROR_RSP, NULL, 0, op->user_data);
+#endif
if (op->destroy)
op->destroy(op->user_data);
@@ -303,7 +297,7 @@ static bool encode_pdu(struct bt_att *att, struct att_send_op *op,
if (pdu_len > 1)
memcpy(op->pdu + 1, pdu, length);
- if (!sign || !(op->opcode & ATT_OP_SIGNED_MASK))
+ if (!sign || !(op->opcode & ATT_OP_SIGNED_MASK) || !att->crypto)
return true;
if (!sign->counter(&sign_cnt, sign->user_data))
@@ -330,33 +324,36 @@ static struct att_send_op *create_att_send_op(struct bt_att *att,
bt_att_destroy_func_t destroy)
{
struct att_send_op *op;
- enum att_op_type op_type;
+ enum att_op_type type;
if (length && !pdu)
return NULL;
- op_type = get_op_type(opcode);
- if (op_type == ATT_OP_TYPE_UNKNOWN)
+ type = get_op_type(opcode);
+ if (type == ATT_OP_TYPE_UNKNOWN)
return NULL;
/* If the opcode corresponds to an operation type that does not elicit a
* response from the remote end, then no callback should have been
* provided, since it will never be called.
*/
- if (callback && op_type != ATT_OP_TYPE_REQ && op_type != ATT_OP_TYPE_IND)
+#ifdef __TIZEN_PATCH__
+ if (callback && type != ATT_OP_TYPE_REQ && type != ATT_OP_TYPE_IND
+ && type != ATT_OP_TYPE_CMD)
+ return NULL;
+#else
+ if (callback && type != ATT_OP_TYPE_REQ && type != ATT_OP_TYPE_IND)
return NULL;
+#endif
/* Similarly, if the operation does elicit a response then a callback
* must be provided.
*/
- if (!callback && (op_type == ATT_OP_TYPE_REQ || op_type == ATT_OP_TYPE_IND))
+ if (!callback && (type == ATT_OP_TYPE_REQ || type == ATT_OP_TYPE_IND))
return NULL;
op = new0(struct att_send_op, 1);
- if (!op)
- return NULL;
-
- op->type = op_type;
+ op->type = type;
op->opcode = opcode;
op->callback = callback;
op->destroy = destroy;
@@ -491,12 +488,21 @@ static bool can_write_data(struct io *io, void *user_data)
case ATT_OP_TYPE_IND:
att->pending_ind = op;
break;
+#ifdef __TIZEN_PATCH__
+ case ATT_OP_TYPE_CMD:
+ if (op->callback)
+ op->callback(0, NULL, 0, op->user_data);
+ destroy_att_send_op(op);
+ return true;
+#endif
case ATT_OP_TYPE_RSP:
/* Set in_req to false to indicate that no request is pending */
att->in_req = false;
/* Fall through to the next case */
+#ifndef __TIZEN_PATCH__
case ATT_OP_TYPE_CMD:
+#endif
case ATT_OP_TYPE_NOT:
case ATT_OP_TYPE_CONF:
case ATT_OP_TYPE_UNKNOWN:
@@ -506,9 +512,6 @@ static bool can_write_data(struct io *io, void *user_data)
}
timeout = new0(struct timeout_data, 1);
- if (!timeout)
- return true;
-
timeout->att = att;
timeout->id = op->id;
op->timeout_id = timeout_add(ATT_TIMEOUT_INTERVAL, timeout_cb,
@@ -585,6 +588,61 @@ static bool disconnect_cb(struct io *io, void *user_data)
return false;
}
+static bool change_security(struct bt_att *att, uint8_t ecode)
+{
+ int security;
+
+ security = bt_att_get_security(att);
+ if (security != BT_ATT_SECURITY_AUTO)
+ return false;
+
+ if (ecode == BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION &&
+ security < BT_ATT_SECURITY_MEDIUM)
+ security = BT_ATT_SECURITY_MEDIUM;
+ else if (ecode == BT_ATT_ERROR_AUTHENTICATION &&
+ security < BT_ATT_SECURITY_HIGH)
+ security = BT_ATT_SECURITY_HIGH;
+ else
+ return false;
+
+ return bt_att_set_security(att, security);
+}
+
+static bool handle_error_rsp(struct bt_att *att, uint8_t *pdu,
+ ssize_t pdu_len, uint8_t *opcode)
+{
+ const struct bt_att_pdu_error_rsp *rsp;
+ struct att_send_op *op = att->pending_req;
+
+ if (pdu_len != sizeof(*rsp)) {
+ *opcode = 0;
+ return false;
+ }
+
+ rsp = (void *) pdu;
+
+ *opcode = rsp->opcode;
+
+ /* Attempt to change security */
+ if (!change_security(att, rsp->ecode))
+ return false;
+
+ util_debug(att->debug_callback, att->debug_data,
+ "Retrying operation %p", op);
+
+ att->pending_req = NULL;
+
+#ifdef __TIZEN_PATCH__
+ if (op->timeout_id) {
+ timeout_remove(op->timeout_id);
+ op->timeout_id = 0;
+ }
+#endif
+
+ /* Push operation back to request queue */
+ return queue_push_head(att->req_queue, op);
+}
+
static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
ssize_t pdu_len)
{
@@ -610,10 +668,11 @@ static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
* the request is malformed, end the current request with failure.
*/
if (opcode == BT_ATT_OP_ERROR_RSP) {
- if (pdu_len != 4)
- goto fail;
-
- req_opcode = pdu[0];
+ /* Return if error response cause a retry */
+ if (handle_error_rsp(att, pdu, pdu_len, &req_opcode)) {
+ wakeup_writer(att);
+ return;
+ }
} else if (!(req_opcode = get_req_opcode(opcode)))
goto fail;
@@ -689,14 +748,13 @@ static bool opcode_match(uint8_t opcode, uint8_t test_opcode)
static void respond_not_supported(struct bt_att *att, uint8_t opcode)
{
- uint8_t pdu[4];
+ struct bt_att_pdu_error_rsp pdu;
- pdu[0] = opcode;
- pdu[1] = 0;
- pdu[2] = 0;
- pdu[3] = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+ pdu.opcode = opcode;
+ pdu.handle = 0x0000;
+ pdu.ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
- bt_att_send(att, BT_ATT_OP_ERROR_RSP, pdu, sizeof(pdu), NULL, NULL,
+ bt_att_send(att, BT_ATT_OP_ERROR_RSP, &pdu, sizeof(pdu), NULL, NULL,
NULL);
}
@@ -743,7 +801,7 @@ static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
const struct queue_entry *entry;
bool found;
- if (opcode & ATT_OP_SIGNED_MASK) {
+ if ((opcode & ATT_OP_SIGNED_MASK) && !att->crypto) {
if (!handle_signed(att, opcode, pdu, pdu_len))
return;
pdu_len -= BT_ATT_SIGNATURE_LEN;
@@ -911,7 +969,7 @@ static void bt_att_free(struct bt_att *att)
free(att);
}
-struct bt_att *bt_att_new(int fd)
+struct bt_att *bt_att_new(int fd, bool ext_signed)
{
struct bt_att *att;
@@ -919,11 +977,7 @@ struct bt_att *bt_att_new(int fd)
return NULL;
att = new0(struct bt_att, 1);
- if (!att)
- return NULL;
-
att->fd = fd;
-
att->mtu = BT_ATT_DEFAULT_LE_MTU;
att->buf = malloc(att->mtu);
if (!att->buf)
@@ -934,27 +988,14 @@ struct bt_att *bt_att_new(int fd)
goto fail;
/* crypto is optional, if not available leave it NULL */
- att->crypto = bt_crypto_new();
+ if (!ext_signed)
+ att->crypto = bt_crypto_new();
att->req_queue = queue_new();
- if (!att->req_queue)
- goto fail;
-
att->ind_queue = queue_new();
- if (!att->ind_queue)
- goto fail;
-
att->write_queue = queue_new();
- if (!att->write_queue)
- goto fail;
-
att->notify_list = queue_new();
- if (!att->notify_list)
- goto fail;
-
att->disconn_list = queue_new();
- if (!att->disconn_list)
- goto fail;
if (!io_set_read_handler(att->io, can_read_data, att, NULL))
goto fail;
@@ -1088,9 +1129,6 @@ unsigned int bt_att_register_disconnect(struct bt_att *att,
return 0;
disconn = new0(struct att_disconn, 1);
- if (!disconn)
- return 0;
-
disconn->callback = callback;
disconn->destroy = destroy;
disconn->user_data = user_data;
@@ -1304,9 +1342,6 @@ unsigned int bt_att_register(struct bt_att *att, uint8_t opcode,
return 0;
notify = new0(struct att_notify, 1);
- if (!notify)
- return 0;
-
notify->opcode = opcode;
notify->callback = callback;
notify->destroy = destroy;
@@ -1352,7 +1387,7 @@ bool bt_att_unregister_all(struct bt_att *att)
return true;
}
-int bt_att_get_sec_level(struct bt_att *att)
+int bt_att_get_security(struct bt_att *att)
{
struct bt_security sec;
socklen_t len;
@@ -1371,11 +1406,12 @@ int bt_att_get_sec_level(struct bt_att *att)
return sec.level;
}
-bool bt_att_set_sec_level(struct bt_att *att, int level)
+bool bt_att_set_security(struct bt_att *att, int level)
{
struct bt_security sec;
- if (!att || level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH)
+ if (!att || level < BT_ATT_SECURITY_AUTO ||
+ level > BT_ATT_SECURITY_HIGH)
return false;
if (!att->io_on_l2cap) {
@@ -1396,11 +1432,8 @@ bool bt_att_set_sec_level(struct bt_att *att, int level)
static bool sign_set_key(struct sign_info **sign, uint8_t key[16],
bt_att_counter_func_t func, void *user_data)
{
- if (!(*sign)) {
+ if (!(*sign))
*sign = new0(struct sign_info, 1);
- if (!(*sign))
- return false;
- }
(*sign)->counter = func;
(*sign)->user_data = user_data;
diff --git a/src/shared/att.h b/src/shared/att.h
index fb6247ec..2a7f87e5 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -28,7 +28,7 @@
struct bt_att;
-struct bt_att *bt_att_new(int fd);
+struct bt_att *bt_att_new(int fd, bool ext_signed);
struct bt_att *bt_att_ref(struct bt_att *att);
void bt_att_unref(struct bt_att *att);
@@ -83,8 +83,8 @@ bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);
bool bt_att_unregister_all(struct bt_att *att);
-int bt_att_get_sec_level(struct bt_att *att);
-bool bt_att_set_sec_level(struct bt_att *att, int level);
+int bt_att_get_security(struct bt_att *att);
+bool bt_att_set_security(struct bt_att *att, int level);
bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
bt_att_counter_func_t func, void *user_data);
diff --git a/src/shared/btsnoop.c b/src/shared/btsnoop.c
index d8be5eac..9dc12519 100644
--- a/src/shared/btsnoop.c
+++ b/src/shared/btsnoop.c
@@ -71,10 +71,11 @@ struct btsnoop {
int ref_count;
int fd;
unsigned long flags;
- uint32_t type;
+ uint32_t format;
uint16_t index;
bool aborted;
bool pklg_format;
+ bool pklg_v2;
#ifdef __TIZEN_PATCH__
char *path;
int16_t rotate_count;
@@ -109,19 +110,21 @@ struct btsnoop *btsnoop_open(const char *path, unsigned long flags)
if (be32toh(hdr.version) != btsnoop_version)
goto failed;
- btsnoop->type = be32toh(hdr.type);
+ btsnoop->format = be32toh(hdr.type);
btsnoop->index = 0xffff;
} else {
if (!(btsnoop->flags & BTSNOOP_FLAG_PKLG_SUPPORT))
goto failed;
/* Check for Apple Packet Logger format */
- if (hdr.id[0] != 0x00 || hdr.id[1] != 0x00)
+ if (hdr.id[0] != 0x00 ||
+ (hdr.id[1] != 0x00 && hdr.id[1] != 0x01))
goto failed;
- btsnoop->type = BTSNOOP_TYPE_MONITOR;
+ btsnoop->format = BTSNOOP_FORMAT_MONITOR;
btsnoop->index = 0xffff;
btsnoop->pklg_format = true;
+ btsnoop->pklg_v2 = (hdr.id[1] == 0x01);
/* Apple Packet Logger format has no header */
lseek(btsnoop->fd, 0, SEEK_SET);
@@ -137,10 +140,10 @@ failed:
}
#ifdef __TIZEN_PATCH__
-struct btsnoop *btsnoop_create(const char *path, uint32_t type,
+struct btsnoop *btsnoop_create(const char *path, uint32_t format,
int16_t rotate_count, ssize_t file_size)
#else
-struct btsnoop *btsnoop_create(const char *path, uint32_t type)
+struct btsnoop *btsnoop_create(const char *path, uint32_t format)
#endif
{
struct btsnoop *btsnoop;
@@ -158,12 +161,12 @@ struct btsnoop *btsnoop_create(const char *path, uint32_t type)
return NULL;
}
- btsnoop->type = type;
+ btsnoop->format = format;
btsnoop->index = 0xffff;
memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
hdr.version = htobe32(btsnoop_version);
- hdr.type = htobe32(btsnoop->type);
+ hdr.type = htobe32(btsnoop->format);
written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
if (written < 0) {
@@ -202,7 +205,7 @@ static int btsnoop_create_2(struct btsnoop *btsnoop)
memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
hdr.version = htobe32(btsnoop_version);
- hdr.type = htobe32(btsnoop->type);
+ hdr.type = htobe32(btsnoop->format);
written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
if (written < 0) {
@@ -294,12 +297,12 @@ void btsnoop_unref(struct btsnoop *btsnoop)
free(btsnoop);
}
-uint32_t btsnoop_get_type(struct btsnoop *btsnoop)
+uint32_t btsnoop_get_format(struct btsnoop *btsnoop)
{
if (!btsnoop)
- return BTSNOOP_TYPE_INVALID;
+ return BTSNOOP_FORMAT_INVALID;
- return btsnoop->type;
+ return btsnoop->format;
}
bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
@@ -360,6 +363,9 @@ static uint32_t get_flags_from_opcode(uint16_t opcode)
case BTSNOOP_OPCODE_SCO_TX_PKT:
case BTSNOOP_OPCODE_SCO_RX_PKT:
break;
+ case BTSNOOP_OPCODE_OPEN_INDEX:
+ case BTSNOOP_OPCODE_CLOSE_INDEX:
+ break;
}
return 0xff;
@@ -374,8 +380,8 @@ bool btsnoop_write_hci(struct btsnoop *btsnoop, struct timeval *tv,
if (!btsnoop)
return false;
- switch (btsnoop->type) {
- case BTSNOOP_TYPE_HCI:
+ switch (btsnoop->format) {
+ case BTSNOOP_FORMAT_HCI:
if (btsnoop->index == 0xffff)
btsnoop->index = index;
@@ -387,7 +393,7 @@ bool btsnoop_write_hci(struct btsnoop *btsnoop, struct timeval *tv,
return false;
break;
- case BTSNOOP_TYPE_MONITOR:
+ case BTSNOOP_FORMAT_MONITOR:
flags = (index << 16) | opcode;
break;
@@ -406,8 +412,8 @@ bool btsnoop_write_phy(struct btsnoop *btsnoop, struct timeval *tv,
if (!btsnoop)
return false;
- switch (btsnoop->type) {
- case BTSNOOP_TYPE_SIMULATOR:
+ switch (btsnoop->format) {
+ case BTSNOOP_FORMAT_SIMULATOR:
flags = (1 << 16) | frequency;
break;
@@ -418,22 +424,6 @@ bool btsnoop_write_phy(struct btsnoop *btsnoop, struct timeval *tv,
return btsnoop_write(btsnoop, tv, flags, data, size);
}
-static uint16_t get_opcode_from_pklg(uint8_t type)
-{
- switch (type) {
- case 0x00:
- return BTSNOOP_OPCODE_COMMAND_PKT;
- case 0x01:
- return BTSNOOP_OPCODE_EVENT_PKT;
- case 0x02:
- return BTSNOOP_OPCODE_ACL_TX_PKT;
- case 0x03:
- return BTSNOOP_OPCODE_ACL_RX_PKT;
- }
-
- return 0xffff;
-}
-
static bool pklg_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
uint16_t *index, uint16_t *opcode,
void *data, uint16_t *size)
@@ -452,14 +442,50 @@ static bool pklg_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
return false;
}
- toread = be32toh(pkt.len) - 9;
+ if (btsnoop->pklg_v2) {
+ toread = le32toh(pkt.len) - (PKLG_PKT_SIZE - 4);
+
+ ts = le64toh(pkt.ts);
+ tv->tv_sec = ts & 0xffffffff;
+ tv->tv_usec = ts >> 32;
+ } else {
+ toread = be32toh(pkt.len) - (PKLG_PKT_SIZE - 4);
- ts = be64toh(pkt.ts);
- tv->tv_sec = ts >> 32;
- tv->tv_usec = ts & 0xffffffff;
+ ts = be64toh(pkt.ts);
+ tv->tv_sec = ts >> 32;
+ tv->tv_usec = ts & 0xffffffff;
+ }
- *index = 0;
- *opcode = get_opcode_from_pklg(pkt.type);
+ switch (pkt.type) {
+ case 0x00:
+ *index = 0x0000;
+ *opcode = BTSNOOP_OPCODE_COMMAND_PKT;
+ break;
+ case 0x01:
+ *index = 0x0000;
+ *opcode = BTSNOOP_OPCODE_EVENT_PKT;
+ break;
+ case 0x02:
+ *index = 0x0000;
+ *opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
+ break;
+ case 0x03:
+ *index = 0x0000;
+ *opcode = BTSNOOP_OPCODE_ACL_RX_PKT;
+ break;
+ case 0x0b:
+ *index = 0x0000;
+ *opcode = BTSNOOP_OPCODE_VENDOR_DIAG;
+ break;
+ case 0xfc:
+ *index = 0xffff;
+ *opcode = BTSNOOP_OPCODE_SYSTEM_NOTE;
+ break;
+ default:
+ *index = 0xffff;
+ *opcode = 0xffff;
+ break;
+ }
len = read(btsnoop->fd, data, toread);
if (len < 0) {
@@ -544,13 +570,13 @@ bool btsnoop_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
tv->tv_sec = (ts / 1000000ll) + 946684800ll;
tv->tv_usec = ts % 1000000ll;
- switch (btsnoop->type) {
- case BTSNOOP_TYPE_HCI:
+ switch (btsnoop->format) {
+ case BTSNOOP_FORMAT_HCI:
*index = 0;
*opcode = get_opcode_from_flags(0xff, flags);
break;
- case BTSNOOP_TYPE_UART:
+ case BTSNOOP_FORMAT_UART:
len = read(btsnoop->fd, &pkt_type, 1);
if (len < 0) {
btsnoop->aborted = true;
@@ -562,7 +588,7 @@ bool btsnoop_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
*opcode = get_opcode_from_flags(pkt_type, flags);
break;
- case BTSNOOP_TYPE_MONITOR:
+ case BTSNOOP_FORMAT_MONITOR:
*index = flags >> 16;
*opcode = flags & 0xffff;
break;
diff --git a/src/shared/btsnoop.h b/src/shared/btsnoop.h
index e5089a80..57e4f500 100644
--- a/src/shared/btsnoop.h
+++ b/src/shared/btsnoop.h
@@ -25,13 +25,13 @@
#include <stdbool.h>
#include <sys/time.h>
-#define BTSNOOP_TYPE_INVALID 0
-#define BTSNOOP_TYPE_HCI 1001
-#define BTSNOOP_TYPE_UART 1002
-#define BTSNOOP_TYPE_BCSP 1003
-#define BTSNOOP_TYPE_3WIRE 1004
-#define BTSNOOP_TYPE_MONITOR 2001
-#define BTSNOOP_TYPE_SIMULATOR 2002
+#define BTSNOOP_FORMAT_INVALID 0
+#define BTSNOOP_FORMAT_HCI 1001
+#define BTSNOOP_FORMAT_UART 1002
+#define BTSNOOP_FORMAT_BCSP 1003
+#define BTSNOOP_FORMAT_3WIRE 1004
+#define BTSNOOP_FORMAT_MONITOR 2001
+#define BTSNOOP_FORMAT_SIMULATOR 2002
#define BTSNOOP_FLAG_PKLG_SUPPORT (1 << 0)
@@ -43,9 +43,26 @@
#define BTSNOOP_OPCODE_ACL_RX_PKT 5
#define BTSNOOP_OPCODE_SCO_TX_PKT 6
#define BTSNOOP_OPCODE_SCO_RX_PKT 7
+#define BTSNOOP_OPCODE_OPEN_INDEX 8
+#define BTSNOOP_OPCODE_CLOSE_INDEX 9
+#define BTSNOOP_OPCODE_INDEX_INFO 10
+#define BTSNOOP_OPCODE_VENDOR_DIAG 11
+#define BTSNOOP_OPCODE_SYSTEM_NOTE 12
+#define BTSNOOP_OPCODE_USER_LOGGING 13
#define BTSNOOP_MAX_PACKET_SIZE (1486 + 4)
+#define BTSNOOP_TYPE_PRIMARY 0
+#define BTSNOOP_TYPE_AMP 1
+
+#define BTSNOOP_BUS_VIRTUAL 0
+#define BTSNOOP_BUS_USB 1
+#define BTSNOOP_BUS_PCCARD 2
+#define BTSNOOP_BUS_UART 3
+#define BTSNOOP_BUS_RS232 4
+#define BTSNOOP_BUS_PCI 5
+#define BTSNOOP_BUS_SDIO 6
+
struct btsnoop_opcode_new_index {
uint8_t type;
uint8_t bus;
@@ -53,20 +70,39 @@ struct btsnoop_opcode_new_index {
char name[8];
} __attribute__((packed));
+struct btsnoop_opcode_index_info {
+ uint8_t bdaddr[6];
+ uint16_t manufacturer;
+} __attribute__((packed));
+
+#define BTSNOOP_PRIORITY_EMERG 0
+#define BTSNOOP_PRIORITY_ALERT 1
+#define BTSNOOP_PRIORITY_CRIT 2
+#define BTSNOOP_PRIORITY_ERR 3
+#define BTSNOOP_PRIORITY_WARNING 4
+#define BTSNOOP_PRIORITY_NOTICE 5
+#define BTSNOOP_PRIORITY_INFO 6
+#define BTSNOOP_PRIORITY_DEBUG 7
+
+struct btsnoop_opcode_user_logging {
+ uint8_t priority;
+ uint8_t ident_len;
+} __attribute__((packed));
+
struct btsnoop;
struct btsnoop *btsnoop_open(const char *path, unsigned long flags);
#ifdef __TIZEN_PATCH__
-struct btsnoop *btsnoop_create(const char *path, uint32_t type,
+struct btsnoop *btsnoop_create(const char *path, uint32_t format,
int16_t rotate_count, ssize_t file_size);
#else
-struct btsnoop *btsnoop_create(const char *path, uint32_t type);
+struct btsnoop *btsnoop_create(const char *path, uint32_t format);
#endif
struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop);
void btsnoop_unref(struct btsnoop *btsnoop);
-uint32_t btsnoop_get_type(struct btsnoop *btsnoop);
+uint32_t btsnoop_get_format(struct btsnoop *btsnoop);
bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
uint32_t flags, const void *data, uint16_t size);
diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index d5cd9158..aa66dac5 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -142,8 +142,6 @@ struct bt_crypto *bt_crypto_new(void)
struct bt_crypto *crypto;
crypto = new0(struct bt_crypto, 1);
- if (!crypto)
- return NULL;
crypto->ecb_aes = ecb_aes_setup();
if (crypto->ecb_aes < 0) {
diff --git a/src/shared/gap.c b/src/shared/gap.c
index cc48a02c..4a21e5d2 100644
--- a/src/shared/gap.c
+++ b/src/shared/gap.c
@@ -162,9 +162,6 @@ struct bt_gap *bt_gap_new_index(uint16_t index)
return NULL;
gap = new0(struct bt_gap, 1);
- if (!gap)
- return NULL;
-
gap->index = index;
gap->mgmt = mgmt_new_default();
@@ -174,7 +171,6 @@ struct bt_gap *bt_gap_new_index(uint16_t index)
}
gap->irk_list = queue_new();
-
gap->mgmt_ready = false;
if (!mgmt_send(gap->mgmt, MGMT_OP_READ_VERSION,
@@ -269,9 +265,6 @@ bool bt_gap_add_peer_irk(struct bt_gap *gap, uint8_t addr_type,
return false;
irk = new0(struct irk_entry, 1);
- if (!irk)
- return false;
-
irk->addr_type = addr_type;
memcpy(irk->addr, addr, 6);
memcpy(irk->key, key, 16);
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 8f97f2be..f8e8298a 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -21,6 +21,10 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "src/shared/att.h"
#include "lib/bluetooth.h"
#include "lib/uuid.h"
@@ -29,8 +33,7 @@
#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-client.h"
-
-#ifdef BLUEZ5_27_GATT_CLIENT
+#if defined __TIZEN_PATCH__ && defined BLUEZ5_27_GATT_CLIENT
#include "../log.h"
#endif
@@ -109,6 +112,12 @@ struct bt_gatt_client {
struct bt_gatt_request *discovery_req;
unsigned int mtu_req_id;
+
+#ifdef __TIZEN_PATCH__
+ char *device_name;
+ struct queue *pending_noti;
+ bool svc_changed_failed;
+#endif
};
struct request {
@@ -123,6 +132,26 @@ struct request {
void (*destroy)(void *);
};
+#ifdef __TIZEN_PATCH__
+struct noti {
+ uint8_t opcode;
+ void *pdu;
+ uint16_t length;
+};
+
+static void notify_cb(uint8_t opcode, const void *pdu, uint16_t length,
+ void *user_data);
+
+static void notification_free(void *data)
+{
+ struct noti *noti = data;
+
+ if (noti->pdu)
+ free(noti->pdu);
+ free(noti);
+}
+#endif
+
static struct request *request_ref(struct request *req)
{
__sync_fetch_and_add(&req->ref_count, 1);
@@ -135,8 +164,6 @@ static struct request *request_create(struct bt_gatt_client *client)
struct request *req;
req = new0(struct request, 1);
- if (!req)
- return NULL;
if (client->next_request_id < 1)
client->next_request_id = 1;
@@ -247,8 +274,6 @@ static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
return NULL;
chrc = new0(struct notify_chrc, 1);
- if (!chrc)
- return NULL;
chrc->reg_notify_queue = queue_new();
if (!chrc->reg_notify_queue) {
@@ -314,6 +339,16 @@ static bool match_notify_chrc_handle_range(const void *a, const void *b)
chrc->value_handle <= range->end;
}
+static void notify_data_cleanup(void *data)
+{
+ struct notify_data *notify_data = data;
+
+ if (notify_data->att_id)
+ bt_att_cancel(notify_data->client->att, notify_data->att_id);
+
+ notify_data_unref(notify_data);
+}
+
static void gatt_client_remove_all_notify_in_range(
struct bt_gatt_client *client,
uint16_t start_handle, uint16_t end_handle)
@@ -324,7 +359,7 @@ static void gatt_client_remove_all_notify_in_range(
range.end = end_handle;
queue_remove_all(client->notify_list, match_notify_data_handle_range,
- &range, notify_data_unref);
+ &range, notify_data_cleanup);
}
static void gatt_client_remove_notify_chrcs_in_range(
@@ -377,21 +412,9 @@ static struct discovery_op *discovery_op_create(struct bt_gatt_client *client,
struct discovery_op *op;
op = new0(struct discovery_op, 1);
- if (!op)
- return NULL;
-
op->pending_svcs = queue_new();
- if (!op->pending_svcs)
- goto fail;
-
op->pending_chrcs = queue_new();
- if (!op->pending_chrcs)
- goto fail;
-
op->tmp_queue = queue_new();
- if (!op->tmp_queue)
- goto fail;
-
op->client = client;
op->complete_func = complete_func;
op->failure_func = failure_func;
@@ -399,10 +422,6 @@ static struct discovery_op *discovery_op_create(struct bt_gatt_client *client,
op->end = end;
return op;
-
-fail:
- discovery_op_free(op);
- return NULL;
}
static struct discovery_op *discovery_op_ref(struct discovery_op *op)
@@ -605,19 +624,16 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
chrc_data->value_handle)
goto failed;
-#ifdef __TIZEN_PATCH__
+ /*
+ * check for descriptors presence, before initializing the
+ * desc_handle and avoid integer overflow during desc_handle
+ * intialization.
+ */
if (chrc_data->value_handle >= chrc_data->end_handle) {
free(chrc_data);
continue;
}
desc_start = chrc_data->value_handle + 1;
-#else
- desc_start = chrc_data->value_handle + 1;
- if (desc_start > chrc_data->end_handle) {
- free(chrc_data);
- continue;
- }
-#endif
client->discovery_req = bt_gatt_discover_descriptors(
client->att, desc_start,
@@ -744,6 +760,56 @@ done:
op->complete_func(op, success, att_ecode);
}
+#ifdef __TIZEN_PATCH__
+static void read_name_cb(bool success, uint8_t att_ecode, const uint8_t *value,
+ uint16_t length, void *user_data)
+{
+ struct bt_gatt_client *client = user_data;
+ char *name;
+
+ if (!success) {
+ util_debug(client->debug_callback, client->debug_data,
+ "read_name_cb failed");
+ return;
+ }
+
+ if (length == 0)
+ return;
+
+ name = malloc(length + 1);
+ if (!name)
+ return;
+
+ memcpy(name, value, length);
+ name[length] = '\0';
+
+ util_debug(client->debug_callback, client->debug_data,
+ "read_name_cb : %s", name);
+
+ if (client->device_name)
+ free(client->device_name);
+
+ client->device_name = name;
+}
+
+bool bt_gatt_request_att_mtu(struct bt_gatt_client *client, uint16_t mtu,
+ void *callback, void *user_data)
+{
+ if (!client || !client->ready)
+ return false;
+
+ /* Configure the MTU */
+ if(!bt_gatt_exchange_mtu(client->att,
+ MAX(BT_ATT_DEFAULT_LE_MTU, mtu),
+ callback,
+ user_data,
+ NULL)) {
+ return false;
+ }
+ return true;
+}
+#endif
+
static void discover_chrcs_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -794,8 +860,6 @@ static void discover_chrcs_cb(bool success, uint8_t att_ecode,
start, end, value, properties, uuid_str);
chrc_data = new0(struct chrc, 1);
- if (!chrc_data)
- goto failed;
chrc_data->start_handle = start;
chrc_data->end_handle = end;
@@ -803,6 +867,16 @@ static void discover_chrcs_cb(bool success, uint8_t att_ecode,
chrc_data->properties = properties;
chrc_data->uuid = uuid;
+#ifdef __TIZEN_PATCH__
+ if (!strcmp(uuid_str, "00002a00-0000-1000-8000-00805f9b34fb")) {
+ if (!bt_gatt_client_read_value(client, chrc_data->value_handle,
+ read_name_cb, client, NULL)) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to read value");
+ }
+ }
+#endif
+
queue_push_tail(op->pending_chrcs, chrc_data);
}
@@ -903,13 +977,21 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
attr = gatt_db_insert_service(client->db, start, &uuid, false,
end - start + 1);
if (!attr) {
- util_debug(client->debug_callback, client->debug_data,
- "Failed to create service");
- success = false;
- goto done;
+ gatt_db_clear_range(client->db, start, end);
+ attr = gatt_db_insert_service(client->db, start, &uuid,
+ false, end - start + 1);
+ if (!attr) {
+ util_debug(client->debug_callback,
+ client->debug_data,
+ "Failed to store service");
+ success = false;
+ goto done;
+ }
}
- queue_push_tail(op->pending_svcs, attr);
+ /* Skip if service already active */
+ if (!gatt_db_service_get_active(attr))
+ queue_push_tail(op->pending_svcs, attr);
}
next:
@@ -917,8 +999,10 @@ next:
attr = queue_pop_head(op->pending_svcs);
/* Complete with success if queue is empty */
- if (!attr)
+ if (!attr) {
+ success = true;
goto done;
+ }
/*
* Store the service in the tmp queue to be reused during
@@ -968,6 +1052,11 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
util_debug(client->debug_callback, client->debug_data,
"Primary service discovery failed."
" ATT ECODE: 0x%02x", att_ecode);
+ /* Reset error in case of not found */
+ if (BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND) {
+ success = true;
+ att_ecode = 0;
+ }
goto secondary;
}
@@ -992,16 +1081,33 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
attr = gatt_db_insert_service(client->db, start, &uuid, true,
end - start + 1);
if (!attr) {
- util_debug(client->debug_callback, client->debug_data,
+ gatt_db_clear_range(client->db, start, end);
+ attr = gatt_db_insert_service(client->db, start, &uuid,
+ true, end - start + 1);
+ if (!attr) {
+ util_debug(client->debug_callback,
+ client->debug_data,
"Failed to store service");
- success = false;
- goto done;
+ success = false;
+ goto done;
+ }
}
- queue_push_tail(op->pending_svcs, attr);
+ /* Skip if service already active */
+ if (!gatt_db_service_get_active(attr))
+ queue_push_tail(op->pending_svcs, attr);
}
secondary:
+ /*
+ * Version 4.2 [Vol 1, Part A] page 101:
+ * A secondary service is a service that provides auxiliary
+ * functionality of a device and is referenced from at least one
+ * primary service on the device.
+ */
+ if (queue_isempty(op->pending_svcs))
+ goto done;
+
/* Discover secondary services */
client->discovery_req = bt_gatt_discover_secondary_services(client->att,
NULL, op->start, op->end,
@@ -1024,10 +1130,11 @@ done:
static void notify_client_ready(struct bt_gatt_client *client, bool success,
uint8_t att_ecode)
{
- if (!client->ready_callback)
+ if (!client->ready_callback || client->ready)
return;
bt_gatt_client_ref(client);
+ client->ready = success;
client->ready_callback(success, att_ecode, client->ready_data);
bt_gatt_client_unref(client);
}
@@ -1045,6 +1152,15 @@ static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data)
"MTU Exchange failed. ATT ECODE: 0x%02x",
att_ecode);
+ /*
+ * BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] page 546
+ * If the Error Response is sent by the server with the Error
+ * Code set to RequestNot Supported , the Attribute Opcode is
+ * not supported and the default MTU shall be used.
+ */
+ if (att_ecode == BT_ATT_ERROR_REQUEST_NOT_SUPPORTED)
+ goto discover;
+
client->in_init = false;
notify_client_ready(client, success, att_ecode);
@@ -1055,12 +1171,10 @@ static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data)
"MTU exchange complete, with MTU: %u",
bt_att_get_mtu(client->att));
- /* Don't do discovery if the database was pre-populated */
- if (!gatt_db_isempty(client->db)) {
- op->complete_func(op, true, 0);
- return;
- }
-
+discover:
+#ifdef __TIZEN_PATCH__
+ op->success = false;
+#endif
client->discovery_req = bt_gatt_discover_all_primary_services(
client->att, NULL,
discover_primary_cb,
@@ -1084,7 +1198,7 @@ struct service_changed_op {
uint16_t end_handle;
};
-#ifdef BLUEZ5_27_GATT_CLIENT
+#if defined __TIZEN_PATCH__ && defined BLUEZ5_27_GATT_CLIENT
bool bt_gatt_discover_services(struct bt_gatt_client *client)
{
struct discovery_op *op;
@@ -1111,28 +1225,189 @@ bool bt_gatt_discover_services(struct bt_gatt_client *client)
}
#endif
-static void service_changed_reregister_cb(uint16_t att_ecode, void *user_data)
+static void process_service_changed(struct bt_gatt_client *client,
+ uint16_t start_handle,
+ uint16_t end_handle);
+static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data);
+
+static void complete_notify_request(void *data)
+{
+ struct notify_data *notify_data = data;
+
+ notify_data->att_id = 0;
+ notify_data->callback(0, notify_data->user_data);
+}
+
+static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable,
+ bt_att_response_func_t callback)
{
- struct bt_gatt_client *client = user_data;
+ uint8_t pdu[4];
+ unsigned int att_id;
+
+ assert(notify_data->chrc->ccc_handle);
+ memset(pdu, 0, sizeof(pdu));
+ put_le16(notify_data->chrc->ccc_handle, pdu);
+
+ if (enable) {
+ /* Try to enable notifications and/or indications based on
+ * whatever the characteristic supports.
+ */
+ if (notify_data->chrc->properties & BT_GATT_CHRC_PROP_NOTIFY)
+ pdu[2] = 0x01;
+
+ if (notify_data->chrc->properties & BT_GATT_CHRC_PROP_INDICATE)
+ pdu[2] |= 0x02;
+
+ if (!pdu[2])
+ return false;
+ }
+
+ att_id = bt_att_send(notify_data->client->att, BT_ATT_OP_WRITE_REQ,
+ pdu, sizeof(pdu), callback,
+ notify_data_ref(notify_data),
+ notify_data_unref);
+ notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
+
+ return !!att_id;
+}
+
+static uint8_t process_error(const void *pdu, uint16_t length)
+{
+ const struct bt_att_pdu_error_rsp *error_pdu;
+
+ if (!pdu || length != sizeof(struct bt_att_pdu_error_rsp))
+ return 0;
+
+ error_pdu = pdu;
+
+ return error_pdu->ecode;
+}
+
+static void enable_ccc_callback(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct notify_data *notify_data = user_data;
+ uint16_t att_ecode;
+
+ assert(notify_data->chrc->ccc_write_id);
+
+ notify_data->chrc->ccc_write_id = 0;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ att_ecode = process_error(pdu, length);
+
+ /* Failed to enable. Complete the current request and move on to
+ * the next one in the queue. If there was an error sending the
+ * write request, then just move on to the next queued entry.
+ */
+ queue_remove(notify_data->client->notify_list, notify_data);
+ notify_data->callback(att_ecode, notify_data->user_data);
+
+ while ((notify_data = queue_pop_head(
+ notify_data->chrc->reg_notify_queue))) {
+
+ if (notify_data_write_ccc(notify_data, true,
+ enable_ccc_callback))
+ return;
+ }
- if (!att_ecode) {
- util_debug(client->debug_callback, client->debug_data,
- "Re-registered handler for \"Service Changed\" after "
- "change in GATT service");
- client->svc_chngd_registered = true;
return;
}
- util_debug(client->debug_callback, client->debug_data,
- "Failed to register handler for \"Service Changed\"");
- client->svc_chngd_ind_id = 0;
+ /* Success! Report success for all remaining requests. */
+ bt_gatt_client_ref(notify_data->client);
+
+ complete_notify_request(notify_data);
+ queue_remove_all(notify_data->chrc->reg_notify_queue, NULL, NULL,
+ complete_notify_request);
+
+ bt_gatt_client_unref(notify_data->client);
}
-static void process_service_changed(struct bt_gatt_client *client,
- uint16_t start_handle,
- uint16_t end_handle);
-static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
- uint16_t length, void *user_data);
+static bool match_notify_chrc_value_handle(const void *a, const void *b)
+{
+ const struct notify_chrc *chrc = a;
+ uint16_t value_handle = PTR_TO_UINT(b);
+
+ return chrc->value_handle == value_handle;
+}
+
+static unsigned int register_notify(struct bt_gatt_client *client,
+ uint16_t handle,
+ bt_gatt_client_register_callback_t callback,
+ bt_gatt_client_notify_callback_t notify,
+ void *user_data,
+ bt_gatt_client_destroy_func_t destroy)
+{
+ struct notify_data *notify_data;
+ struct notify_chrc *chrc = NULL;
+
+ /* Check if a characteristic ref count has been started already */
+ chrc = queue_find(client->notify_chrcs, match_notify_chrc_value_handle,
+ UINT_TO_PTR(handle));
+
+ if (!chrc) {
+ /*
+ * Create an entry if the characteristic is known and has a CCC
+ * descriptor.
+ */
+ chrc = notify_chrc_create(client, handle);
+ if (!chrc)
+ return 0;
+ }
+
+ /* Fail if we've hit the maximum allowed notify sessions */
+ if (chrc->notify_count == INT_MAX)
+ return 0;
+
+ notify_data = new0(struct notify_data, 1);
+ notify_data->client = client;
+ notify_data->ref_count = 1;
+ notify_data->chrc = chrc;
+ notify_data->callback = callback;
+ notify_data->notify = notify;
+ notify_data->user_data = user_data;
+ notify_data->destroy = destroy;
+
+ /* Add the handler to the bt_gatt_client's general list */
+ queue_push_tail(client->notify_list, notify_data);
+
+ /* Assign an ID to the handler. */
+ if (client->next_reg_id < 1)
+ client->next_reg_id = 1;
+
+ notify_data->id = client->next_reg_id++;
+
+ /* Increment the per-characteristic ref count of notify handlers */
+ __sync_fetch_and_add(&notify_data->chrc->notify_count, 1);
+
+ /*
+ * If a write to the CCC descriptor is in progress, then queue this
+ * request.
+ */
+ if (chrc->ccc_write_id) {
+ queue_push_tail(chrc->reg_notify_queue, notify_data);
+ return notify_data->id;
+ }
+
+ /*
+ * If the ref count > 1, then notifications are already enabled.
+ */
+ if (chrc->notify_count > 1 || !chrc->ccc_handle) {
+ complete_notify_request(notify_data);
+ return notify_data->id;
+ }
+
+ /* Write to the CCC descriptor */
+ if (!notify_data_write_ccc(notify_data, true, enable_ccc_callback)) {
+ queue_remove(client->notify_list, notify_data);
+ free(notify_data);
+ return 0;
+ }
+
+ return notify_data->id;
+}
static void get_first_attribute(struct gatt_db_attribute *attrib,
void *user_data)
@@ -1145,6 +1420,75 @@ static void get_first_attribute(struct gatt_db_attribute *attrib,
*stored = attrib;
}
+static void service_changed_register_cb(uint16_t att_ecode, void *user_data)
+{
+ bool success;
+ struct bt_gatt_client *client = user_data;
+
+ if (att_ecode) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to register handler for \"Service Changed\"");
+ success = false;
+ client->svc_chngd_ind_id = 0;
+ goto done;
+ }
+
+ client->svc_chngd_registered = true;
+ success = true;
+ util_debug(client->debug_callback, client->debug_data,
+ "Registered handler for \"Service Changed\": %u",
+ client->svc_chngd_ind_id);
+
+done:
+ notify_client_ready(client, success, att_ecode);
+
+#ifdef __TIZEN_PATCH__
+ if (success) {
+ struct noti *noti;
+
+ while ((noti = queue_pop_head(client->pending_noti))) {
+ notify_cb(noti->opcode, noti->pdu,
+ noti->length, client);
+ notification_free(noti);
+ }
+ } else {
+ util_debug(client->debug_callback, client->debug_data,
+ "Remove all pending notifications");
+ queue_remove_all(client->pending_noti, NULL, NULL,
+ notification_free);
+ }
+#endif
+}
+
+static bool register_service_changed(struct bt_gatt_client *client)
+{
+ bt_uuid_t uuid;
+ struct gatt_db_attribute *attr = NULL;
+
+ bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
+
+ if (client->svc_chngd_ind_id)
+ return true;
+
+ gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid,
+ get_first_attribute, &attr);
+ if (!attr)
+ return true;
+
+ /*
+ * Register an indication handler for the "Service Changed"
+ * characteristic and report ready only if the handler is registered
+ * successfully.
+ */
+ client->svc_chngd_ind_id = register_notify(client,
+ gatt_db_attribute_get_handle(attr),
+ service_changed_register_cb,
+ service_changed_cb,
+ client, NULL);
+
+ return client->svc_chngd_ind_id ? true : false;
+}
+
static void service_changed_complete(struct discovery_op *op, bool success,
uint8_t att_ecode)
{
@@ -1152,8 +1496,6 @@ static void service_changed_complete(struct discovery_op *op, bool success,
struct service_changed_op *next_sc_op;
uint16_t start_handle = op->start;
uint16_t end_handle = op->end;
- struct gatt_db_attribute *attr = NULL;
- bt_uuid_t uuid;
client->in_svc_chngd = false;
@@ -1162,6 +1504,9 @@ static void service_changed_complete(struct discovery_op *op, bool success,
"Failed to discover services within changed range - "
"error: 0x%02x", att_ecode);
+#ifdef __TIZEN_PATCH__
+ client->svc_changed_failed = true;
+#endif
gatt_db_clear_range(client->db, start_handle, end_handle);
}
@@ -1179,23 +1524,7 @@ static void service_changed_complete(struct discovery_op *op, bool success,
return;
}
- bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
-
- gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid,
- get_first_attribute, &attr);
- if (!attr)
- return;
-
- /* The GATT service was modified. Re-register the handler for
- * indications from the "Service Changed" characteristic.
- */
- client->svc_chngd_registered = false;
- client->svc_chngd_ind_id = bt_gatt_client_register_notify(client,
- gatt_db_attribute_get_handle(attr),
- service_changed_reregister_cb,
- service_changed_cb,
- client, NULL);
- if (client->svc_chngd_ind_id)
+ if (register_service_changed(client))
return;
util_debug(client->debug_callback, client->debug_data,
@@ -1206,6 +1535,11 @@ static void service_changed_failure(struct discovery_op *op)
{
struct bt_gatt_client *client = op->client;
+#ifdef __TIZEN_PATCH__
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to discover services");
+#endif
+
gatt_db_clear_range(client->db, op->start, op->end);
}
@@ -1215,6 +1549,10 @@ static void process_service_changed(struct bt_gatt_client *client,
{
struct discovery_op *op;
+ /* On full database reset just re-run attribute discovery */
+ if (start_handle == 0x0001 && end_handle == 0xffff)
+ goto discover;
+
/* Invalidate and remove all effected notify callbacks */
gatt_client_remove_all_notify_in_range(client, start_handle,
end_handle);
@@ -1226,6 +1564,7 @@ static void process_service_changed(struct bt_gatt_client *client,
*/
gatt_db_clear_range(client->db, start_handle, end_handle);
+discover:
op = discovery_op_create(client, start_handle, end_handle,
service_changed_complete,
service_changed_failure);
@@ -1257,8 +1596,14 @@ static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
struct service_changed_op *op;
uint16_t start, end;
- if (length != 4)
+ if (length != 4) {
+#ifdef __TIZEN_PATCH__
+ util_debug(client->debug_callback, client->debug_data,
+ "Service changed is received with invalid length : %d",
+ length);
+#endif
return;
+ }
start = get_le16(value);
end = get_le16(value + 2);
@@ -1273,14 +1618,14 @@ static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
"Service Changed received - start: 0x%04x end: 0x%04x",
start, end);
+#ifndef __TIZEN_PATCH__
if (!client->in_svc_chngd) {
process_service_changed(client, start, end);
return;
}
+#endif
op = new0(struct service_changed_op, 1);
- if (!op)
- return;
op->start_handle = start;
op->end_handle = end;
@@ -1288,68 +1633,18 @@ static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
queue_push_tail(client->svc_chngd_queue, op);
}
-static void service_changed_register_cb(uint16_t att_ecode, void *user_data)
-{
- bool success;
- struct bt_gatt_client *client = user_data;
-
- if (att_ecode) {
- util_debug(client->debug_callback, client->debug_data,
- "Failed to register handler for \"Service Changed\"");
- success = false;
- client->svc_chngd_ind_id = 0;
- goto done;
- }
-
- client->svc_chngd_registered = true;
- client->ready = true;
- success = true;
- util_debug(client->debug_callback, client->debug_data,
- "Registered handler for \"Service Changed\": %u",
- client->svc_chngd_ind_id);
-
-done:
- notify_client_ready(client, success, att_ecode);
-}
-
static void init_complete(struct discovery_op *op, bool success,
uint8_t att_ecode)
{
struct bt_gatt_client *client = op->client;
- struct gatt_db_attribute *attr = NULL;
- bt_uuid_t uuid;
client->in_init = false;
if (!success)
goto fail;
- bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
-
- gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid,
- get_first_attribute, &attr);
- if (!attr) {
- client->ready = true;
+ if (register_service_changed(client))
goto done;
- }
-
- /* Register an indication handler for the "Service Changed"
- * characteristic and report ready only if the handler is registered
- * successfully. Temporarily set "ready" to true so that we can register
- * the handler using the existing framework.
- */
- client->ready = true;
- client->svc_chngd_ind_id = bt_gatt_client_register_notify(client,
- gatt_db_attribute_get_handle(attr),
- service_changed_register_cb,
- service_changed_cb,
- client, NULL);
-
- if (!client->svc_chngd_registered)
- client->ready = false;
-
- if (client->svc_chngd_ind_id)
- return;
util_debug(client->debug_callback, client->debug_data,
"Failed to register handler for \"Service Changed\"");
@@ -1363,12 +1658,34 @@ fail:
done:
notify_client_ready(client, success, att_ecode);
+
+#ifdef __TIZEN_PATCH__
+ if (success) {
+ struct noti *noti;
+
+ while ((noti = queue_pop_head(client->pending_noti))) {
+ notify_cb(noti->opcode, noti->pdu,
+ noti->length, client);
+ notification_free(noti);
+ }
+ } else {
+ util_debug(client->debug_callback, client->debug_data,
+ "Remove all pending notifications");
+ queue_remove_all(client->pending_noti, NULL, NULL,
+ notification_free);
+ }
+#endif
}
static void init_fail(struct discovery_op *op)
{
struct bt_gatt_client *client = op->client;
+#ifdef __TIZEN_PATCH__
+ util_debug(client->debug_callback, client->debug_data,
+ "GATT client init is failed");
+#endif
+
gatt_db_clear(client->db);
}
@@ -1405,111 +1722,12 @@ struct pdu_data {
uint16_t length;
};
-static void complete_notify_request(void *data)
-{
- struct notify_data *notify_data = data;
-
- /* Increment the per-characteristic ref count of notify handlers */
- __sync_fetch_and_add(&notify_data->chrc->notify_count, 1);
-
- notify_data->att_id = 0;
- notify_data->callback(0, notify_data->user_data);
-}
-
-static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable,
- bt_att_response_func_t callback)
-{
- uint8_t pdu[4];
- unsigned int att_id;
-
- assert(notify_data->chrc->ccc_handle);
- memset(pdu, 0, sizeof(pdu));
- put_le16(notify_data->chrc->ccc_handle, pdu);
-
- if (enable) {
- /* Try to enable notifications and/or indications based on
- * whatever the characteristic supports.
- */
- if (notify_data->chrc->properties & BT_GATT_CHRC_PROP_NOTIFY)
- pdu[2] = 0x01;
-
- if (notify_data->chrc->properties & BT_GATT_CHRC_PROP_INDICATE)
- pdu[2] |= 0x02;
-
- if (!pdu[2])
- return false;
- }
-
- att_id = bt_att_send(notify_data->client->att, BT_ATT_OP_WRITE_REQ,
- pdu, sizeof(pdu), callback,
- notify_data_ref(notify_data),
- notify_data_unref);
- notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
-
- return !!att_id;
-}
-
-static uint8_t process_error(const void *pdu, uint16_t length)
-{
- const struct bt_att_pdu_error_rsp *error_pdu;
-
- if (!pdu || length != sizeof(struct bt_att_pdu_error_rsp))
- return 0;
-
- error_pdu = pdu;
-
- return error_pdu->ecode;
-}
-
-static void enable_ccc_callback(uint8_t opcode, const void *pdu,
- uint16_t length, void *user_data)
-{
- struct notify_data *notify_data = user_data;
- uint16_t att_ecode;
-
- assert(!notify_data->chrc->notify_count);
- assert(notify_data->chrc->ccc_write_id);
-
- notify_data->chrc->ccc_write_id = 0;
-
- if (opcode == BT_ATT_OP_ERROR_RSP) {
- att_ecode = process_error(pdu, length);
-
- /* Failed to enable. Complete the current request and move on to
- * the next one in the queue. If there was an error sending the
- * write request, then just move on to the next queued entry.
- */
- queue_remove(notify_data->client->notify_list, notify_data);
- notify_data->callback(att_ecode, notify_data->user_data);
-
- while ((notify_data = queue_pop_head(
- notify_data->chrc->reg_notify_queue))) {
-
- if (notify_data_write_ccc(notify_data, true,
- enable_ccc_callback))
- return;
- }
-
- return;
- }
-
- /* Success! Report success for all remaining requests. */
- bt_gatt_client_ref(notify_data->client);
-
- complete_notify_request(notify_data);
- queue_remove_all(notify_data->chrc->reg_notify_queue, NULL, NULL,
- complete_notify_request);
-
- bt_gatt_client_unref(notify_data->client);
-}
-
static void disable_ccc_callback(uint8_t opcode, const void *pdu,
uint16_t length, void *user_data)
{
struct notify_data *notify_data = user_data;
struct notify_data *next_data;
- assert(!notify_data->chrc->notify_count);
assert(notify_data->chrc->ccc_write_id);
notify_data->chrc->ccc_write_id = 0;
@@ -1542,8 +1760,7 @@ static void complete_unregister_notify(void *data)
!notify_data->chrc->ccc_handle)
goto done;
- if (notify_data_write_ccc(notify_data, false, disable_ccc_callback))
- return;
+ notify_data_write_ccc(notify_data, false, disable_ccc_callback);
done:
notify_data_unref(notify_data);
@@ -1578,6 +1795,36 @@ static void notify_cb(uint8_t opcode, const void *pdu, uint16_t length,
{
struct bt_gatt_client *client = user_data;
struct pdu_data pdu_data;
+#ifdef __TIZEN_PATCH__
+ struct service_changed_op *sc_op;
+
+ if (client->ready == false) {
+ struct noti *noti;
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Client is not ready. pend notification.");
+
+ noti = new0(struct noti, 1);
+ if (!noti)
+ return;
+
+ noti->pdu = malloc(length);
+ if (!noti->pdu) {
+ free(noti);
+ return;
+ }
+
+ noti->opcode = opcode;
+ noti->length = length;
+ memcpy(noti->pdu, pdu, length);
+
+ util_debug(client->debug_callback, client->debug_data,
+ "Notification handle : %d", get_le16(pdu));
+
+ queue_push_tail(client->pending_noti, noti);
+ return;
+ }
+#endif
bt_gatt_client_ref(client);
@@ -1587,6 +1834,15 @@ static void notify_cb(uint8_t opcode, const void *pdu, uint16_t length,
queue_foreach(client->notify_list, notify_handler, &pdu_data);
+#ifdef __TIZEN_PATCH__
+ if (client->in_svc_chngd == false &&
+ (sc_op = queue_pop_head(client->svc_chngd_queue))) {
+ process_service_changed(client, sc_op->start_handle,
+ sc_op->end_handle);
+ free(sc_op);
+ }
+#endif
+
if (opcode == BT_ATT_OP_HANDLE_VAL_IND)
bt_att_send(client->att, BT_ATT_OP_HANDLE_VAL_CONF, NULL, 0,
NULL, NULL, NULL);
@@ -1594,16 +1850,6 @@ static void notify_cb(uint8_t opcode, const void *pdu, uint16_t length,
bt_gatt_client_unref(client);
}
-static void notify_data_cleanup(void *data)
-{
- struct notify_data *notify_data = data;
-
- if (notify_data->att_id)
- bt_att_cancel(notify_data->client->att, notify_data->att_id);
-
- notify_data_unref(notify_data);
-}
-
static void bt_gatt_client_free(struct bt_gatt_client *client)
{
bt_gatt_client_cancel_all(client);
@@ -1623,6 +1869,16 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
bt_att_unref(client->att);
}
+#ifdef __TIZEN_PATCH__
+ if (client->in_svc_chngd || client->svc_changed_failed) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Service changed is going. Clear DB");
+ gatt_db_clear(client->db);
+ }
+
+ queue_destroy(client->pending_noti, notification_free);
+#endif
+
gatt_db_unref(client->db);
queue_destroy(client->svc_chngd_queue, free);
@@ -1630,6 +1886,13 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
queue_destroy(client->notify_chrcs, notify_chrc_free);
queue_destroy(client->pending_requests, request_unref);
+#ifdef __TIZEN_PATCH__
+ if (client->device_name) {
+ free(client->device_name);
+ client->device_name = NULL;
+ }
+#endif
+
free(client);
}
@@ -1660,33 +1923,19 @@ struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
return NULL;
client = new0(struct bt_gatt_client, 1);
- if (!client)
- return NULL;
-
client->disc_id = bt_att_register_disconnect(att, att_disconnect_cb,
client, NULL);
if (!client->disc_id)
goto fail;
client->long_write_queue = queue_new();
- if (!client->long_write_queue)
- goto fail;
-
client->svc_chngd_queue = queue_new();
- if (!client->svc_chngd_queue)
- goto fail;
-
client->notify_list = queue_new();
- if (!client->notify_list)
- goto fail;
-
client->notify_chrcs = queue_new();
- if (!client->notify_chrcs)
- goto fail;
-
client->pending_requests = queue_new();
- if (!client->pending_requests)
- goto fail;
+#ifdef __TIZEN_PATCH__
+ client->pending_noti = queue_new();
+#endif
client->notify_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_NOT,
notify_cb, client, NULL);
@@ -1798,6 +2047,14 @@ uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client)
return bt_att_get_mtu(client->att);
}
+struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client)
+{
+ if (!client || !client->db)
+ return NULL;
+
+ return client->db;
+}
+
static bool match_req_id(const void *a, const void *b)
{
const struct request *req = a;
@@ -1964,8 +2221,6 @@ unsigned int bt_gatt_client_read_value(struct bt_gatt_client *client,
return 0;
op = new0(struct read_op, 1);
- if (!op)
- return 0;
req = request_create(client);
if (!req) {
@@ -2043,8 +2298,6 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
return 0;
op = new0(struct read_op, 1);
- if (!op)
- return 0;
req = request_create(client);
if (!req) {
@@ -2193,8 +2446,6 @@ unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client,
return 0;
op = new0(struct read_long_op, 1);
- if (!op)
- return 0;
req = request_create(client);
if (!req) {
@@ -2228,6 +2479,93 @@ unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client,
return req->id;
}
+#ifdef __TIZEN_PATCH__
+struct write_cmd_op {
+ struct bt_gatt_client *client;
+ bt_gatt_client_callback_t callback;
+ void *user_data;
+ bt_gatt_destroy_func_t destroy;
+};
+
+static void destroy_write_cmd_op(void *data)
+{
+ struct write_cmd_op *op = data;
+
+ if (op->destroy)
+ op->destroy(op->user_data);
+
+ free(op);
+}
+
+static void write_cmd_cb(uint8_t opcode, const void *pdu, uint16_t length,
+ void *user_data)
+{
+ struct request *req = user_data;
+ struct write_cmd_op *op = req->data;
+ bool success = true;
+ uint8_t att_ecode = 0;
+
+ if (op->callback)
+ op->callback(success, att_ecode, op->user_data);
+}
+
+unsigned int bt_gatt_client_write_without_response_async(
+ struct bt_gatt_client *client,
+ uint16_t value_handle,
+ bool signed_write,
+ const uint8_t *value, uint16_t length,
+ bt_gatt_client_callback_t callback,
+ void *user_data,
+ bt_gatt_client_destroy_func_t destroy)
+{
+
+ uint8_t pdu[2 + length];
+ struct request *req;
+ struct write_cmd_op *op;
+ int security;
+ uint8_t opcode;
+
+ if (!client)
+ return 0;
+
+ op = new0(struct write_cmd_op, 1);
+ if (!op)
+ return 0;
+
+ req = request_create(client);
+ if (!req)
+ return 0;
+
+ op->callback = callback;
+ op->user_data = user_data;
+ op->destroy = destroy;
+
+ req->data = op;
+ req->destroy = destroy_write_cmd_op;
+
+ /* Only use signed write if unencrypted */
+ if (signed_write) {
+ security = bt_att_get_security(client->att);
+ opcode = security > BT_SECURITY_LOW ? BT_ATT_OP_WRITE_CMD :
+ BT_ATT_OP_SIGNED_WRITE_CMD;
+ } else
+ opcode = BT_ATT_OP_WRITE_CMD;
+
+ put_le16(value_handle, pdu);
+ memcpy(pdu + 2, value, length);
+
+ req->att_id = bt_att_send(client->att, opcode,
+ pdu, sizeof(pdu), write_cmd_cb, req, request_unref);
+ if (!req->att_id) {
+ op->destroy = NULL;
+ request_unref(req);
+ return 0;
+ }
+
+ return req->id;
+}
+#endif
+
unsigned int bt_gatt_client_write_without_response(
struct bt_gatt_client *client,
uint16_t value_handle,
@@ -2247,7 +2585,7 @@ unsigned int bt_gatt_client_write_without_response(
/* Only use signed write if unencrypted */
if (signed_write) {
- security = bt_att_get_sec_level(client->att);
+ security = bt_att_get_security(client->att);
op = security > BT_SECURITY_LOW ? BT_ATT_OP_WRITE_CMD :
BT_ATT_OP_SIGNED_WRITE_CMD;
} else
@@ -2320,8 +2658,6 @@ unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client,
return 0;
op = new0(struct write_op, 1);
- if (!op)
- return 0;
req = request_create(client);
if (!req) {
@@ -2460,11 +2796,15 @@ static void execute_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
} else if (opcode != BT_ATT_OP_EXEC_WRITE_RSP || pdu || length)
success = false;
+ bt_gatt_client_ref(op->client);
+
if (op->callback)
op->callback(success, op->reliable_error, att_ecode,
op->user_data);
start_next_long_write(op->client);
+
+ bt_gatt_client_unref(op->client);
}
static void complete_write_long_op(struct request *req, bool success,
@@ -2490,14 +2830,17 @@ static void complete_write_long_op(struct request *req, bool success,
if (req->att_id)
return;
-
request_unref(req);
success = false;
+ bt_gatt_client_ref(op->client);
+
if (op->callback)
op->callback(success, reliable_error, att_ecode, op->user_data);
start_next_long_write(op->client);
+
+ bt_gatt_client_unref(op->client);
}
static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
@@ -2588,9 +2931,6 @@ unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
return 0;
op = new0(struct long_write_op, 1);
- if (!op)
- return 0;
-
op->value = malloc(length);
if (!op->value) {
free(op);
@@ -2719,8 +3059,6 @@ static struct request *get_reliable_request(struct bt_gatt_client *client,
struct prep_write_op *op;
op = new0(struct prep_write_op, 1);
- if (!op)
- return NULL;
/* Following prepare writes */
if (id != 0)
@@ -2879,8 +3217,6 @@ unsigned int bt_gatt_client_write_execute(struct bt_gatt_client *client,
return 0;
op = new0(struct write_op, 1);
- if (!op)
- return 0;
req = queue_find(client->pending_requests, match_req_id,
UINT_TO_PTR(id));
@@ -2911,14 +3247,6 @@ unsigned int bt_gatt_client_write_execute(struct bt_gatt_client *client,
return id;
}
-static bool match_notify_chrc_value_handle(const void *a, const void *b)
-{
- const struct notify_chrc *chrc = a;
- uint16_t value_handle = PTR_TO_UINT(b);
-
- return chrc->value_handle == value_handle;
-}
-
unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
uint16_t chrc_value_handle,
bt_gatt_client_register_callback_t callback,
@@ -2926,79 +3254,14 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
void *user_data,
bt_gatt_client_destroy_func_t destroy)
{
- struct notify_data *notify_data;
- struct notify_chrc *chrc = NULL;
-
if (!client || !client->db || !chrc_value_handle || !callback)
return 0;
- if (!bt_gatt_client_is_ready(client) || client->in_svc_chngd)
- return 0;
-
- /* Check if a characteristic ref count has been started already */
- chrc = queue_find(client->notify_chrcs, match_notify_chrc_value_handle,
- UINT_TO_PTR(chrc_value_handle));
-
- if (!chrc) {
- /*
- * Create an entry if the characteristic is known and has a CCC
- * descriptor.
- */
- chrc = notify_chrc_create(client, chrc_value_handle);
- if (!chrc)
- return 0;
- }
-
- /* Fail if we've hit the maximum allowed notify sessions */
- if (chrc->notify_count == INT_MAX)
- return 0;
-
- notify_data = new0(struct notify_data, 1);
- if (!notify_data)
+ if (client->in_svc_chngd)
return 0;
- notify_data->client = client;
- notify_data->ref_count = 1;
- notify_data->chrc = chrc;
- notify_data->callback = callback;
- notify_data->notify = notify;
- notify_data->user_data = user_data;
- notify_data->destroy = destroy;
-
- /* Add the handler to the bt_gatt_client's general list */
- queue_push_tail(client->notify_list, notify_data);
-
- /* Assign an ID to the handler. */
- if (client->next_reg_id < 1)
- client->next_reg_id = 1;
-
- notify_data->id = client->next_reg_id++;
-
- /*
- * If a write to the CCC descriptor is in progress, then queue this
- * request.
- */
- if (chrc->ccc_write_id) {
- queue_push_tail(chrc->reg_notify_queue, notify_data);
- return notify_data->id;
- }
-
- /*
- * If the ref count is not zero, then notifications are already enabled.
- */
- if (chrc->notify_count > 0 || !chrc->ccc_handle) {
- complete_notify_request(notify_data);
- return notify_data->id;
- }
-
- /* Write to the CCC descriptor */
- if (!notify_data_write_ccc(notify_data, true, enable_ccc_callback)) {
- queue_remove(client->notify_list, notify_data);
- free(notify_data);
- return 0;
- }
-
- return notify_data->id;
+ return register_notify(client, chrc_value_handle, callback, notify,
+ user_data, destroy);
}
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
@@ -3014,26 +3277,43 @@ bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
if (!notify_data)
return false;
- assert(notify_data->chrc->notify_count > 0);
- assert(!notify_data->chrc->ccc_write_id);
+ /* Remove data if it has been queued */
+ queue_remove(notify_data->chrc->reg_notify_queue, notify_data);
complete_unregister_notify(notify_data);
return true;
}
-bool bt_gatt_client_set_sec_level(struct bt_gatt_client *client,
- int level)
+bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level)
{
if (!client)
return false;
- return bt_att_set_sec_level(client->att, level);
+ return bt_att_set_security(client->att, level);
}
-int bt_gatt_client_get_sec_level(struct bt_gatt_client *client)
+int bt_gatt_client_get_security(struct bt_gatt_client *client)
{
if (!client)
return -1;
- return bt_att_get_sec_level(client->att);
+ return bt_att_get_security(client->att);
}
+
+#ifdef __TIZEN_PATCH__
+char *bt_gatt_client_get_gap_device_name(struct bt_gatt_client *client)
+{
+ if (!client)
+ return NULL;
+
+ return client->device_name;
+}
+
+bool bt_gatt_client_svc_changed_received(struct bt_gatt_client *client)
+{
+ if (!client)
+ return false;
+
+ return client->in_svc_chngd;
+}
+#endif
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 13303c6f..8e310ca9 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -70,6 +70,7 @@ bool bt_gatt_client_set_debug(struct bt_gatt_client *client,
bt_gatt_client_destroy_func_t destroy);
uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client);
+struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client);
bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id);
bool bt_gatt_client_cancel_all(struct bt_gatt_client *client);
@@ -90,6 +91,17 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
void *user_data,
bt_gatt_client_destroy_func_t destroy);
+#ifdef __TIZEN_PATCH__
+unsigned int bt_gatt_client_write_without_response_async(
+ struct bt_gatt_client *client,
+ uint16_t value_handle,
+ bool signed_write,
+ const uint8_t *value, uint16_t length,
+ bt_gatt_client_callback_t callback,
+ void *user_data,
+ bt_gatt_client_destroy_func_t destroy);
+#endif
+
unsigned int bt_gatt_client_write_without_response(
struct bt_gatt_client *client,
uint16_t value_handle,
@@ -130,9 +142,16 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
unsigned int id);
-bool bt_gatt_client_set_sec_level(struct bt_gatt_client *client, int level);
-int bt_gatt_client_get_sec_level(struct bt_gatt_client *client);
+bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level);
+int bt_gatt_client_get_security(struct bt_gatt_client *client);
-#ifdef BLUEZ5_27_GATT_CLIENT
+#if defined __TIZEN_PATCH__ && defined BLUEZ5_27_GATT_CLIENT
bool bt_gatt_discover_services(struct bt_gatt_client *client);
#endif
+
+#ifdef __TIZEN_PATCH__
+char *bt_gatt_client_get_gap_device_name(struct bt_gatt_client *client);
+bool bt_gatt_request_att_mtu(struct bt_gatt_client *client, uint16_t mtu,
+ void *callback, void *user_data);
+bool bt_gatt_client_svc_changed_received(struct bt_gatt_client *client);
+#endif
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index ea0d2c32..d741abcb 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -21,6 +21,10 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdbool.h>
#include <errno.h>
@@ -170,8 +174,6 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
struct gatt_db_attribute *attribute;
attribute = new0(struct gatt_db_attribute, 1);
- if (!attribute)
- return NULL;
attribute->service = service;
attribute->handle = handle;
@@ -186,12 +188,7 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
}
attribute->pending_reads = queue_new();
- if (!attribute->pending_reads)
- goto failed;
-
attribute->pending_writes = queue_new();
- if (!attribute->pending_reads)
- goto failed;
return attribute;
@@ -215,22 +212,8 @@ struct gatt_db *gatt_db_new(void)
struct gatt_db *db;
db = new0(struct gatt_db, 1);
- if (!db)
- return NULL;
-
db->services = queue_new();
- if (!db->services) {
- free(db);
- return NULL;
- }
-
db->notify_list = queue_new();
- if (!db->notify_list) {
- queue_destroy(db->services, NULL);
- free(db);
- return NULL;
- }
-
db->next_handle = 0x0001;
return gatt_db_ref(db);
@@ -390,14 +373,7 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
return NULL;
service = new0(struct gatt_db_service, 1);
- if (!service)
- return NULL;
-
service->attributes = new0(struct gatt_db_attribute *, num_handles);
- if (!service->attributes) {
- free(service);
- return NULL;
- }
if (primary)
type = &primary_service_uuid;
@@ -490,7 +466,8 @@ bool gatt_db_clear_range(struct gatt_db *db, uint16_t start_handle,
return true;
}
-static bool find_insert_loc(struct gatt_db *db, uint16_t start, uint16_t end,
+static struct gatt_db_service *find_insert_loc(struct gatt_db *db,
+ uint16_t start, uint16_t end,
struct gatt_db_service **after)
{
const struct queue_entry *services_entry;
@@ -507,19 +484,19 @@ static bool find_insert_loc(struct gatt_db *db, uint16_t start, uint16_t end,
gatt_db_service_get_handles(service, &cur_start, &cur_end);
if (start >= cur_start && start <= cur_end)
- return false;
+ return service;
if (end >= cur_start && end <= cur_end)
- return false;
+ return service;
if (end < cur_start)
- return true;
+ return NULL;
*after = service;
services_entry = services_entry->next;
}
- return true;
+ return NULL;
}
struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
@@ -538,8 +515,28 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
if (num_handles < 1 || (handle + num_handles - 1) > UINT16_MAX)
return NULL;
- if (!find_insert_loc(db, handle, handle + num_handles - 1, &after))
+ service = find_insert_loc(db, handle, handle + num_handles - 1, &after);
+ if (service) {
+ const bt_uuid_t *type;
+ bt_uuid_t value;
+
+ if (primary)
+ type = &primary_service_uuid;
+ else
+ type = &secondary_service_uuid;
+
+ gatt_db_attribute_get_service_uuid(service->attributes[0],
+ &value);
+
+ /* Check if service match */
+ if (!bt_uuid_cmp(&service->attributes[0]->uuid, type) &&
+ !bt_uuid_cmp(&value, uuid) &&
+ service->num_handles == num_handles &&
+ service->attributes[0]->handle == handle)
+ return service->attributes[0];
+
return NULL;
+ }
service = gatt_db_service_create(uuid, handle, primary, num_handles);
@@ -588,9 +585,6 @@ unsigned int gatt_db_register(struct gatt_db *db,
return 0;
notify = new0(struct notify, 1);
- if (!notify)
- return 0;
-
notify->service_added = service_added;
notify->service_removed = service_removed;
notify->destroy = destroy;
@@ -689,6 +683,18 @@ service_insert_characteristic(struct gatt_db_service *service,
if (handle && handle <= service->attributes[0]->handle)
return NULL;
+ /*
+ * It is not possible to allocate last handle for a Characteristic
+ * since it would not have space for its value:
+ * 3.3.2 Characteristic Value Declaration
+ * The Characteristic Value declaration contains the value of the
+ * characteristic. It is the first Attribute after the characteristic
+ * declaration. All characteristic definitions shall have a
+ * Characteristic Value declaration.
+ */
+ if (handle == UINT16_MAX)
+ return NULL;
+
i = get_attribute_index(service, 1);
if (!i)
return NULL;
@@ -715,6 +721,9 @@ service_insert_characteristic(struct gatt_db_service *service,
service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
if (!service->attributes[i]) {
free(service->attributes[i - 1]);
+#ifdef __TIZEN_PATCH__
+ service->attributes[i - 1] = NULL;
+#endif
return NULL;
}
@@ -1562,9 +1571,6 @@ bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
struct pending_read *p;
p = new0(struct pending_read, 1);
- if (!p)
- return false;
-
p->attrib = attrib;
p->id = ++attrib->read_id;
p->timeout_id = timeout_add(ATTRIBUTE_TIMEOUT, read_timeout,
@@ -1646,9 +1652,6 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
struct pending_write *p;
p = new0(struct pending_write, 1);
- if (!p)
- return false;
-
p->attrib = attrib;
p->id = ++attrib->write_id;
p->timeout_id = timeout_add(ATTRIBUTE_TIMEOUT, write_timeout,
@@ -1752,7 +1755,7 @@ void set_ccc_unicast_address(const struct gatt_db_attribute *ccc,
bdaddr_t *get_ccc_unicast_address(const struct gatt_db_attribute *ccc)
{
if (ccc)
- return (bdaddr_t *)&ccc->unicast_addr;
+ return &ccc->unicast_addr;
return NULL;
}
#endif
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 1076a6a4..a0a5b267 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -56,9 +56,6 @@ static struct bt_gatt_result *result_create(uint8_t opcode, const void *pdu,
struct bt_gatt_result *result;
result = new0(struct bt_gatt_result, 1);
- if (!result)
- return NULL;
-
result->pdu = malloc(pdu_len);
if (!result->pdu) {
free(result);
@@ -110,7 +107,7 @@ unsigned int bt_gatt_result_service_count(struct bt_gatt_result *result)
return 0;
if (result->opcode != BT_ATT_OP_READ_BY_GRP_TYPE_RSP &&
- result->opcode != BT_ATT_OP_FIND_BY_TYPE_VAL_RSP)
+ result->opcode != BT_ATT_OP_FIND_BY_TYPE_RSP)
return 0;
return result_element_count(result);
@@ -345,7 +342,7 @@ bool bt_gatt_iter_next_service(struct bt_gatt_iter *iter,
*end_handle = get_le16(pdu_ptr + 2);
convert_uuid_le(pdu_ptr + 4, iter->result->data_len - 4, uuid);
break;
- case BT_ATT_OP_FIND_BY_TYPE_VAL_RSP:
+ case BT_ATT_OP_FIND_BY_TYPE_RSP:
*start_handle = get_le16(pdu_ptr);
*end_handle = get_le16(pdu_ptr + 2);
@@ -549,9 +546,6 @@ unsigned int bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
return false;
op = new0(struct mtu_op, 1);
- if (!op)
- return false;
-
op->att = att;
op->client_rx_mtu = client_rx_mtu;
op->callback = callback;
@@ -753,7 +747,7 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
/* PDU must contain 4 bytes and it must be a multiple of 4, where each
* 4 bytes contain the 16-bit attribute and group end handles.
*/
- if (opcode != BT_ATT_OP_FIND_BY_TYPE_VAL_RSP || !pdu || !length ||
+ if (opcode != BT_ATT_OP_FIND_BY_TYPE_RSP || !pdu || !length ||
length % 4) {
success = false;
goto done;
@@ -791,7 +785,7 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
put_le16(op->service_type, pdu + 4);
bt_uuid_to_le(&op->uuid, pdu + 6);
- op->id = bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+ op->id = bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_REQ,
pdu, sizeof(pdu),
find_by_type_val_cb,
bt_gatt_request_ref(op),
@@ -823,9 +817,6 @@ static struct bt_gatt_request *discover_services(struct bt_att *att,
return NULL;
op = new0(struct bt_gatt_request, 1);
- if (!op)
- return NULL;
-
op->att = att;
op->start_handle = start;
op->end_handle = end;
@@ -864,7 +855,7 @@ static struct bt_gatt_request *discover_services(struct bt_att *att,
put_le16(op->service_type, pdu + 4);
bt_uuid_to_le(&op->uuid, pdu + 6);
- op->id = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+ op->id = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_REQ,
pdu, sizeof(pdu),
find_by_type_val_cb,
bt_gatt_request_ref(op),
@@ -924,9 +915,6 @@ static struct read_incl_data *new_read_included(struct bt_gatt_result *res)
struct read_incl_data *data;
data = new0(struct read_incl_data, 1);
- if (!data)
- return NULL;
-
data->op = bt_gatt_request_ref(res->op);
data->result = res;
@@ -1161,9 +1149,6 @@ struct bt_gatt_request *bt_gatt_discover_included_services(struct bt_att *att,
return false;
op = new0(struct bt_gatt_request, 1);
- if (!op)
- return false;
-
op->att = att;
op->callback = callback;
op->user_data = user_data;
@@ -1259,6 +1244,8 @@ static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
goto done;
}
+ success = true;
+
done:
discovery_op_complete(op, success, att_ecode);
}
@@ -1276,9 +1263,6 @@ struct bt_gatt_request *bt_gatt_discover_characteristics(struct bt_att *att,
return false;
op = new0(struct bt_gatt_request, 1);
- if (!op)
- return false;
-
op->att = att;
op->callback = callback;
op->user_data = user_data;
@@ -1386,9 +1370,6 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
return false;
op = new0(struct bt_gatt_request, 1);
- if (!op)
- return false;
-
op->att = att;
op->callback = callback;
op->user_data = user_data;
@@ -1488,6 +1469,7 @@ static void discover_descs_cb(uint8_t opcode, const void *pdu,
return;
success = false;
+ goto done;
}
success = true;
@@ -1509,9 +1491,6 @@ struct bt_gatt_request *bt_gatt_discover_descriptors(struct bt_att *att,
return false;
op = new0(struct bt_gatt_request, 1);
- if (!op)
- return false;
-
op->att = att;
op->callback = callback;
op->user_data = user_data;
diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index 1485e8c9..127e45b9 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
@@ -21,6 +21,10 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <sys/uio.h>
#include <errno.h>
@@ -176,7 +180,7 @@ static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q,
int iter = 0;
uint16_t start_handle, end_handle;
struct iovec value;
- uint8_t data_val_len = 0;
+ uint8_t data_val_len;
*len = 0;
@@ -248,10 +252,6 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
}
q = queue_new();
- if (!q) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
start = get_le16(pdu);
end = get_le16(pdu + 2);
@@ -377,12 +377,39 @@ done:
process_read_by_type(op);
}
+static uint8_t check_permissions(struct bt_gatt_server *server,
+ struct gatt_db_attribute *attr, uint32_t mask)
+{
+ uint32_t perm;
+ int security;
+
+ perm = gatt_db_attribute_get_permissions(attr);
+
+ if (perm && mask & BT_ATT_PERM_READ && !(perm & BT_ATT_PERM_READ))
+ return BT_ATT_ERROR_READ_NOT_PERMITTED;
+
+ if (perm && mask & BT_ATT_PERM_WRITE && !(perm & BT_ATT_PERM_WRITE))
+ return BT_ATT_ERROR_WRITE_NOT_PERMITTED;
+
+ perm &= mask;
+ if (!perm)
+ return 0;
+
+ security = bt_att_get_security(server->att);
+ if (perm & BT_ATT_PERM_AUTHEN && security < BT_ATT_SECURITY_HIGH)
+ return BT_ATT_ERROR_AUTHENTICATION;
+
+ if (perm & BT_ATT_PERM_ENCRYPT && security < BT_ATT_SECURITY_MEDIUM)
+ return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION;
+
+ return 0;
+}
+
static void process_read_by_type(struct async_read_op *op)
{
struct bt_gatt_server *server = op->server;
uint8_t ecode;
struct gatt_db_attribute *attr;
- uint32_t perm;
attr = queue_pop_head(op->db_data);
@@ -395,18 +422,11 @@ static void process_read_by_type(struct async_read_op *op)
return;
}
- perm = gatt_db_attribute_get_permissions(attr);
-
- /*
- * Check for the READ access permission. Encryption,
- * authentication, and authorization permissions need to be
- * checked by the read handler, since bt_att is agnostic to
- * connection type and doesn't have security information on it.
- */
- if (perm && !(perm & BT_ATT_PERM_READ)) {
- ecode = BT_ATT_ERROR_READ_NOT_PERMITTED;
+ ecode = check_permissions(server, attr, BT_ATT_PERM_READ |
+ BT_ATT_PERM_READ_AUTHEN |
+ BT_ATT_PERM_READ_ENCRYPT);
+ if (ecode)
goto error;
- }
if (gatt_db_attribute_read(attr, 0, op->opcode, server->att,
read_by_type_read_complete_cb, op))
@@ -437,10 +457,6 @@ static void read_by_type_cb(uint8_t opcode, const void *pdu,
}
q = queue_new();
- if (!q) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
start = get_le16(pdu);
end = get_le16(pdu + 2);
@@ -475,11 +491,6 @@ static void read_by_type_cb(uint8_t opcode, const void *pdu,
}
op = new0(struct async_read_op, 1);
- if (!op) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
-
op->pdu = malloc(bt_att_get_mtu(server->att));
if (!op->pdu) {
free(op);
@@ -508,7 +519,7 @@ static bool encode_find_info_rsp(struct gatt_db *db, struct queue *q,
uint16_t handle;
struct gatt_db_attribute *attr;
const bt_uuid_t *type;
- int uuid_len = 0, cur_uuid_len;
+ int uuid_len, cur_uuid_len;
int iter = 0;
*len = 0;
@@ -573,10 +584,6 @@ static void find_info_cb(uint8_t opcode, const void *pdu,
}
q = queue_new();
- if (!q) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
start = get_le16(pdu);
end = get_le16(pdu + 2);
@@ -704,7 +711,7 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
if (data.ecode)
goto error;
- bt_att_send(server->att, BT_ATT_OP_FIND_BY_TYPE_VAL_RSP, data.pdu,
+ bt_att_send(server->att, BT_ATT_OP_FIND_BY_TYPE_RSP, data.pdu,
data.len, NULL, NULL, NULL);
return;
@@ -752,7 +759,6 @@ static void write_cb(uint8_t opcode, const void *pdu,
uint16_t handle = 0;
struct async_write_op *op = NULL;
uint8_t ecode;
- uint32_t perm;
if (length < 2) {
ecode = BT_ATT_ERROR_INVALID_PDU;
@@ -771,27 +777,33 @@ static void write_cb(uint8_t opcode, const void *pdu,
(opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd",
handle);
- perm = gatt_db_attribute_get_permissions(attr);
-
- if (!(perm & BT_ATT_PERM_WRITE)) {
- ecode = BT_ATT_ERROR_WRITE_NOT_PERMITTED;
+ ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE |
+ BT_ATT_PERM_WRITE_AUTHEN |
+ BT_ATT_PERM_WRITE_ENCRYPT);
+ if (ecode)
goto error;
- }
if (server->pending_write_op) {
+#ifdef __TIZEN_PATCH__
+ if (opcode != BT_ATT_OP_WRITE_CMD) {
+#endif
ecode = BT_ATT_ERROR_UNLIKELY;
goto error;
+#ifdef __TIZEN_PATCH__
+ }
+#endif
}
op = new0(struct async_write_op, 1);
- if (!op) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
-
op->server = server;
op->opcode = opcode;
+
+#ifdef __TIZEN_PATCH__
+ if (opcode != BT_ATT_OP_WRITE_CMD)
+ server->pending_write_op = op;
+#else
server->pending_write_op = op;
+#endif
if (gatt_db_attribute_write(attr, 0, pdu + 2, length - 2, opcode,
server->att,
@@ -804,6 +816,13 @@ static void write_cb(uint8_t opcode, const void *pdu,
ecode = BT_ATT_ERROR_UNLIKELY;
error:
+#ifdef __TIZEN_PATCH__
+ util_debug(server->debug_callback, server->debug_data,
+ "Handling \"Write %s\" is failed : %d",
+ (opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd",
+ ecode);
+#endif
+
if (opcode == BT_ATT_OP_WRITE_CMD)
return;
@@ -871,7 +890,6 @@ static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode,
{
struct gatt_db_attribute *attr;
uint8_t ecode;
- uint32_t perm;
struct async_read_op *op = NULL;
attr = gatt_db_get_attribute(server->db, handle);
@@ -885,12 +903,11 @@ static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode,
opcode == BT_ATT_OP_READ_BLOB_REQ ? "Blob " : "",
handle);
- perm = gatt_db_attribute_get_permissions(attr);
-
- if (perm && !(perm & BT_ATT_PERM_READ)) {
- ecode = BT_ATT_ERROR_READ_NOT_PERMITTED;
+ ecode = check_permissions(server, attr, BT_ATT_PERM_READ |
+ BT_ATT_PERM_READ_AUTHEN |
+ BT_ATT_PERM_READ_ENCRYPT);
+ if (ecode)
goto error;
- }
if (server->pending_read_op) {
ecode = BT_ATT_ERROR_UNLIKELY;
@@ -898,11 +915,6 @@ static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode,
}
op = new0(struct async_read_op, 1);
- if (!op) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
-
op->opcode = opcode;
op->server = server;
server->pending_read_op = op;
@@ -980,8 +992,8 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err,
{
struct read_multiple_resp_data *data = user_data;
struct gatt_db_attribute *next_attr;
- uint32_t perm;
uint16_t handle = gatt_db_attribute_get_handle(attr);
+ uint8_t ecode;
if (err != 0) {
bt_att_send_error_rsp(data->server->att,
@@ -990,12 +1002,12 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err,
return;
}
- perm = gatt_db_attribute_get_permissions(attr);
-
- if (perm && !(perm & BT_ATT_PERM_READ)) {
+ ecode = check_permissions(data->server, attr, BT_ATT_PERM_READ |
+ BT_ATT_PERM_READ_AUTHEN |
+ BT_ATT_PERM_READ_ENCRYPT);
+ if (ecode) {
bt_att_send_error_rsp(data->server->att,
- BT_ATT_OP_READ_MULT_REQ, handle,
- BT_ATT_ERROR_READ_NOT_PERMITTED);
+ BT_ATT_OP_READ_MULT_REQ, handle, ecode);
read_multiple_resp_data_free(data);
return;
}
@@ -1072,9 +1084,6 @@ static void read_multiple_cb(uint8_t opcode, const void *pdu,
data.handles = new0(uint16_t, data.num_handles);
- if (!data.handles)
- goto error;
-
for (i = 0; i < data.num_handles; i++)
data.handles[i] = get_le16(pdu + i * 2);
@@ -1107,7 +1116,6 @@ static void prep_write_cb(uint8_t opcode, const void *pdu,
uint16_t offset;
struct gatt_db_attribute *attr;
uint8_t ecode;
- uint32_t perm;
if (length < 4) {
ecode = BT_ATT_ERROR_INVALID_PDU;
@@ -1131,26 +1139,13 @@ static void prep_write_cb(uint8_t opcode, const void *pdu,
util_debug(server->debug_callback, server->debug_data,
"Prep Write Req - handle: 0x%04x", handle);
- perm = gatt_db_attribute_get_permissions(attr);
-
- /*
- * TODO: The "Prepare Write" request requires security permission checks
- * to be performed before the write is executed. I.e., we can't leave
- * the permission check to the upper layer since we can't call
- * gatt_db_write until the entire queue is atomically processed during
- * an "Execute Write" request. Figure out how to make this check here.
- */
- if (!(perm & BT_ATT_PERM_WRITE)) {
- ecode = BT_ATT_ERROR_WRITE_NOT_PERMITTED;
+ ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE |
+ BT_ATT_PERM_WRITE_AUTHEN |
+ BT_ATT_PERM_WRITE_ENCRYPT);
+ if (ecode)
goto error;
- }
prep_data = new0(struct prep_write_data, 1);
- if (!prep_data) {
- ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
- goto error;
- }
-
prep_data->length = length - 4;
if (prep_data->length) {
prep_data->value = malloc(prep_data->length);
@@ -1290,6 +1285,7 @@ static void exchange_mtu_cb(uint8_t opcode, const void *pdu,
}
client_rx_mtu = get_le16(pdu);
+#ifndef __TIZEN_PACTH__
final_mtu = MAX(MIN(client_rx_mtu, server->mtu), BT_ATT_DEFAULT_LE_MTU);
/* Respond with the server MTU */
@@ -1300,6 +1296,18 @@ static void exchange_mtu_cb(uint8_t opcode, const void *pdu,
/* Set MTU to be the minimum */
server->mtu = final_mtu;
bt_att_set_mtu(server->att, final_mtu);
+#else
+ final_mtu = MAX(MIN(client_rx_mtu, BT_ATT_MAX_LE_MTU), BT_ATT_DEFAULT_LE_MTU);
+
+ /* Set MTU to be the minimum */
+ server->mtu = final_mtu;
+ bt_att_set_mtu(server->att, final_mtu);
+
+ /* Respond with the server MTU */
+ put_le16(server->mtu, rsp_pdu);
+ bt_att_send(server->att, BT_ATT_OP_MTU_RSP, rsp_pdu, 2, NULL, NULL,
+ NULL);
+#endif
util_debug(server->debug_callback, server->debug_data,
"MTU exchange complete, with MTU: %u", final_mtu);
@@ -1340,7 +1348,7 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server)
/* Find By Type Value */
server->find_by_type_value_id = bt_att_register(server->att,
- BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+ BT_ATT_OP_FIND_BY_TYPE_REQ,
find_by_type_val_cb,
server, NULL);
@@ -1411,19 +1419,11 @@ struct bt_gatt_server *bt_gatt_server_new(struct gatt_db *db,
return NULL;
server = new0(struct bt_gatt_server, 1);
- if (!server)
- return NULL;
-
server->db = gatt_db_ref(db);
server->att = bt_att_ref(att);
server->mtu = MAX(mtu, BT_ATT_DEFAULT_LE_MTU);
server->max_prep_queue_len = DEFAULT_MAX_PREP_QUEUE_LEN;
-
server->prep_queue = queue_new();
- if (!server->prep_queue) {
- bt_gatt_server_free(server);
- return NULL;
- }
if (!gatt_server_register_att_handlers(server)) {
bt_gatt_server_free(server);
@@ -1544,10 +1544,6 @@ bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
return false;
data = new0(struct ind_data, 1);
- if (!data) {
- free(pdu);
- return false;
- }
data->callback = callback;
data->destroy = destroy;
diff --git a/src/shared/hci-crypto.c b/src/shared/hci-crypto.c
index 8a40aa5a..f7507472 100644
--- a/src/shared/hci-crypto.c
+++ b/src/shared/hci-crypto.c
@@ -66,9 +66,6 @@ static bool le_encrypt(struct bt_hci *hci, uint8_t size,
memcpy(cmd.plaintext, plaintext, 16);
data = new0(struct crypto_data, 1);
- if (!data)
- return false;
-
data->size = size;
data->callback = callback;
data->user_data = user_data;
@@ -110,9 +107,6 @@ bool bt_hci_crypto_prand(struct bt_hci *hci,
return false;
data = new0(struct crypto_data, 1);
- if (!data)
- return false;
-
data->callback = callback;
data->user_data = user_data;
diff --git a/src/shared/hci.c b/src/shared/hci.c
index 0db0146b..bfee4ab3 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -290,9 +290,6 @@ static struct bt_hci *create_hci(int fd)
return NULL;
hci = new0(struct bt_hci, 1);
- if (!hci)
- return NULL;
-
hci->io = io_new(fd);
if (!hci->io) {
free(hci);
@@ -306,28 +303,8 @@ static struct bt_hci *create_hci(int fd)
hci->next_evt_id = 1;
hci->cmd_queue = queue_new();
- if (!hci->cmd_queue) {
- io_destroy(hci->io);
- free(hci);
- return NULL;
- }
-
hci->rsp_queue = queue_new();
- if (!hci->rsp_queue) {
- queue_destroy(hci->cmd_queue, NULL);
- io_destroy(hci->io);
- free(hci);
- return NULL;
- }
-
hci->evt_list = queue_new();
- if (!hci->evt_list) {
- queue_destroy(hci->rsp_queue, NULL);
- queue_destroy(hci->cmd_queue, NULL);
- io_destroy(hci->io);
- free(hci);
- return NULL;
- }
if (!io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
queue_destroy(hci->evt_list, NULL);
@@ -476,9 +453,6 @@ unsigned int bt_hci_send(struct bt_hci *hci, uint16_t opcode,
return 0;
cmd = new0(struct cmd, 1);
- if (!cmd)
- return 0;
-
cmd->opcode = opcode;
cmd->size = size;
@@ -568,9 +542,6 @@ unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
return 0;
evt = new0(struct evt, 1);
- if (!evt)
- return 0;
-
evt->event = event;
if (hci->next_evt_id < 1)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 74ee979c..d9f7659c 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -575,9 +575,6 @@ struct hfp_gw *hfp_gw_new(int fd)
return NULL;
hfp = new0(struct hfp_gw, 1);
- if (!hfp)
- return NULL;
-
hfp->fd = fd;
hfp->close_on_unref = false;
@@ -603,13 +600,6 @@ struct hfp_gw *hfp_gw_new(int fd)
}
hfp->cmd_handlers = queue_new();
- if (!hfp->cmd_handlers) {
- io_destroy(hfp->io);
- ringbuf_free(hfp->write_buf);
- ringbuf_free(hfp->read_buf);
- free(hfp);
- return NULL;
- }
if (!io_set_read_handler(hfp->io, can_read_data, hfp,
read_watch_destroy)) {
@@ -844,9 +834,6 @@ bool hfp_gw_register(struct hfp_gw *hfp, hfp_result_func_t callback,
struct cmd_handler *handler;
handler = new0(struct cmd_handler, 1);
- if (!handler)
- return false;
-
handler->callback = callback;
handler->user_data = user_data;
@@ -1262,9 +1249,6 @@ struct hfp_hf *hfp_hf_new(int fd)
return NULL;
hfp = new0(struct hfp_hf, 1);
- if (!hfp)
- return NULL;
-
hfp->fd = fd;
hfp->close_on_unref = false;
@@ -1290,24 +1274,7 @@ struct hfp_hf *hfp_hf_new(int fd)
}
hfp->event_handlers = queue_new();
- if (!hfp->event_handlers) {
- io_destroy(hfp->io);
- ringbuf_free(hfp->write_buf);
- ringbuf_free(hfp->read_buf);
- free(hfp);
- return NULL;
- }
-
hfp->cmd_queue = queue_new();
- if (!hfp->cmd_queue) {
- io_destroy(hfp->io);
- ringbuf_free(hfp->write_buf);
- ringbuf_free(hfp->read_buf);
- queue_destroy(hfp->event_handlers, NULL);
- free(hfp);
- return NULL;
- }
-
hfp->writer_active = false;
if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
@@ -1440,10 +1407,6 @@ bool hfp_hf_send_command(struct hfp_hf *hfp, hfp_response_func_t resp_cb,
return false;
cmd = new0(struct cmd_response, 1);
- if (!cmd) {
- free(fmt);
- return false;
- }
va_start(ap, format);
len = ringbuf_vprintf(hfp->write_buf, fmt, ap);
@@ -1481,9 +1444,6 @@ bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
return false;
handler = new0(struct event_handler, 1);
- if (!handler)
- return false;
-
handler->callback = callback;
handler->user_data = user_data;
diff --git a/src/shared/io-mainloop.c b/src/shared/io-mainloop.c
index 49237105..2306c347 100644
--- a/src/shared/io-mainloop.c
+++ b/src/shared/io-mainloop.c
@@ -160,9 +160,6 @@ struct io *io_new(int fd)
return NULL;
io = new0(struct io, 1);
- if (!io)
- return NULL;
-
io->fd = fd;
io->events = 0;
io->close_on_destroy = false;
diff --git a/src/shared/mgmt.c b/src/shared/mgmt.c
index 1ed635d2..277e361a 100644
--- a/src/shared/mgmt.c
+++ b/src/shared/mgmt.c
@@ -51,6 +51,8 @@ struct mgmt {
struct queue *notify_list;
unsigned int next_request_id;
unsigned int next_notify_id;
+ bool need_notify_cleanup;
+ bool in_notify;
void *buf;
uint16_t len;
mgmt_debug_func_t debug_callback;
@@ -73,6 +75,7 @@ struct mgmt_notify {
unsigned int id;
uint16_t event;
uint16_t index;
+ bool removed;
mgmt_notify_func_t callback;
mgmt_destroy_func_t destroy;
void *user_data;
@@ -131,6 +134,22 @@ static bool match_notify_index(const void *a, const void *b)
return notify->index == index;
}
+static bool match_notify_removed(const void *a, const void *b)
+{
+ const struct mgmt_notify *notify = a;
+
+ return notify->removed;
+}
+
+static void mark_notify_removed(void *data , void *user_data)
+{
+ struct mgmt_notify *notify = data;
+ uint16_t index = PTR_TO_UINT(user_data);
+
+ if (notify->index == index || index == MGMT_INDEX_NONE)
+ notify->removed = true;
+}
+
static void write_watch_destroy(void *user_data)
{
struct mgmt *mgmt = user_data;
@@ -260,6 +279,9 @@ static void notify_handler(void *data, void *user_data)
struct mgmt_notify *notify = data;
struct event_index *match = user_data;
+ if (notify->removed)
+ return;
+
if (notify->event != match->event)
return;
@@ -277,7 +299,17 @@ static void process_notify(struct mgmt *mgmt, uint16_t event, uint16_t index,
struct event_index match = { .event = event, .index = index,
.length = length, .param = param };
+ mgmt->in_notify = true;
+
queue_foreach(mgmt->notify_list, notify_handler, &match);
+
+ mgmt->in_notify = false;
+
+ if (mgmt->need_notify_cleanup) {
+ queue_remove_all(mgmt->notify_list, match_notify_removed,
+ NULL, destroy_notify);
+ mgmt->need_notify_cleanup = false;
+ }
}
static bool can_read_data(struct io *io, void *user_data)
@@ -353,9 +385,6 @@ struct mgmt *mgmt_new(int fd)
return NULL;
mgmt = new0(struct mgmt, 1);
- if (!mgmt)
- return NULL;
-
mgmt->fd = fd;
mgmt->close_on_unref = false;
@@ -374,42 +403,9 @@ struct mgmt *mgmt_new(int fd)
}
mgmt->request_queue = queue_new();
- if (!mgmt->request_queue) {
- io_destroy(mgmt->io);
- free(mgmt->buf);
- free(mgmt);
- return NULL;
- }
-
mgmt->reply_queue = queue_new();
- if (!mgmt->reply_queue) {
- queue_destroy(mgmt->request_queue, NULL);
- io_destroy(mgmt->io);
- free(mgmt->buf);
- free(mgmt);
- return NULL;
- }
-
mgmt->pending_list = queue_new();
- if (!mgmt->pending_list) {
- queue_destroy(mgmt->reply_queue, NULL);
- queue_destroy(mgmt->request_queue, NULL);
- io_destroy(mgmt->io);
- free(mgmt->buf);
- free(mgmt);
- return NULL;
- }
-
mgmt->notify_list = queue_new();
- if (!mgmt->notify_list) {
- queue_destroy(mgmt->pending_list, NULL);
- queue_destroy(mgmt->reply_queue, NULL);
- queue_destroy(mgmt->request_queue, NULL);
- io_destroy(mgmt->io);
- free(mgmt->buf);
- free(mgmt);
- return NULL;
- }
if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {
queue_destroy(mgmt->notify_list, NULL);
@@ -501,11 +497,12 @@ void mgmt_unref(struct mgmt *mgmt)
free(mgmt->buf);
mgmt->buf = NULL;
- queue_destroy(mgmt->notify_list, NULL);
- queue_destroy(mgmt->pending_list, NULL);
- free(mgmt);
-
- return;
+ if (!mgmt->in_notify) {
+ queue_destroy(mgmt->notify_list, NULL);
+ queue_destroy(mgmt->pending_list, NULL);
+ free(mgmt);
+ return;
+ }
}
bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
@@ -549,9 +546,6 @@ static struct mgmt_request *create_request(uint16_t opcode, uint16_t index,
return NULL;
request = new0(struct mgmt_request, 1);
- if (!request)
- return NULL;
-
request->len = length + MGMT_HDR_SIZE;
request->buf = malloc(request->len);
if (!request->buf) {
@@ -732,9 +726,6 @@ unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
return 0;
notify = new0(struct mgmt_notify, 1);
- if (!notify)
- return 0;
-
notify->event = event;
notify->index = index;
@@ -767,7 +758,14 @@ bool mgmt_unregister(struct mgmt *mgmt, unsigned int id)
if (!notify)
return false;
- destroy_notify(notify);
+ if (!mgmt->in_notify) {
+ destroy_notify(notify);
+ return true;
+ }
+
+ notify->removed = true;
+ mgmt->need_notify_cleanup = true;
+
return true;
}
@@ -776,7 +774,12 @@ bool mgmt_unregister_index(struct mgmt *mgmt, uint16_t index)
if (!mgmt)
return false;
- queue_remove_all(mgmt->notify_list, match_notify_index,
+ if (mgmt->in_notify) {
+ queue_foreach(mgmt->notify_list, mark_notify_removed,
+ UINT_TO_PTR(index));
+ mgmt->need_notify_cleanup = true;
+ } else
+ queue_remove_all(mgmt->notify_list, match_notify_index,
UINT_TO_PTR(index), destroy_notify);
return true;
@@ -787,7 +790,12 @@ bool mgmt_unregister_all(struct mgmt *mgmt)
if (!mgmt)
return false;
- queue_remove_all(mgmt->notify_list, NULL, NULL, destroy_notify);
+ if (mgmt->in_notify) {
+ queue_foreach(mgmt->notify_list, mark_notify_removed,
+ UINT_TO_PTR(MGMT_INDEX_NONE));
+ mgmt->need_notify_cleanup = true;
+ } else
+ queue_remove_all(mgmt->notify_list, NULL, NULL, destroy_notify);
return true;
}
diff --git a/src/shared/queue.c b/src/shared/queue.c
index 3507ed16..5ddb8326 100644
--- a/src/shared/queue.c
+++ b/src/shared/queue.c
@@ -58,9 +58,6 @@ struct queue *queue_new(void)
struct queue *queue;
queue = new0(struct queue, 1);
- if (!queue)
- return NULL;
-
queue->head = NULL;
queue->tail = NULL;
queue->entries = 0;
@@ -78,35 +75,14 @@ void queue_destroy(struct queue *queue, queue_destroy_func_t destroy)
queue_unref(queue);
}
-static struct queue_entry *queue_entry_ref(struct queue_entry *entry)
-{
- if (!entry)
- return NULL;
-
- __sync_fetch_and_add(&entry->ref_count, 1);
-
- return entry;
-}
-
-static void queue_entry_unref(struct queue_entry *entry)
-{
- if (__sync_sub_and_fetch(&entry->ref_count, 1))
- return;
-
- free(entry);
-}
-
static struct queue_entry *queue_entry_new(void *data)
{
struct queue_entry *entry;
entry = new0(struct queue_entry, 1);
- if (!entry)
- return NULL;
-
entry->data = data;
- return queue_entry_ref(entry);
+ return entry;
}
bool queue_push_tail(struct queue *queue, void *data)
@@ -117,8 +93,6 @@ bool queue_push_tail(struct queue *queue, void *data)
return false;
entry = queue_entry_new(data);
- if (!entry)
- return false;
if (queue->tail)
queue->tail->next = entry;
@@ -141,8 +115,6 @@ bool queue_push_head(struct queue *queue, void *data)
return false;
entry = queue_entry_new(data);
- if (!entry)
- return false;
entry->next = queue->head;
@@ -176,8 +148,6 @@ bool queue_push_after(struct queue *queue, void *entry, void *data)
return false;
new_entry = queue_entry_new(data);
- if (!new_entry)
- return false;
new_entry->next = qentry->next;
@@ -208,7 +178,7 @@ void *queue_pop_head(struct queue *queue)
data = entry->data;
- queue_entry_unref(entry);
+ free(entry);
queue->entries--;
return data;
@@ -246,14 +216,8 @@ void queue_foreach(struct queue *queue, queue_foreach_func_t function,
while (entry && queue->head && queue->ref_count > 1) {
struct queue_entry *next;
- queue_entry_ref(entry);
-
- function(entry->data, user_data);
-
next = entry->next;
-
- queue_entry_unref(entry);
-
+ function(entry->data, user_data);
entry = next;
}
queue_unref(queue);
@@ -302,7 +266,7 @@ bool queue_remove(struct queue *queue, void *data)
if (!entry->next)
queue->tail = prev;
- queue_entry_unref(entry);
+ free(entry);
queue->entries--;
return true;
@@ -335,7 +299,7 @@ void *queue_remove_if(struct queue *queue, queue_match_func_t function,
data = entry->data;
- queue_entry_unref(entry);
+ free(entry);
queue->entries--;
return data;
@@ -386,7 +350,7 @@ unsigned int queue_remove_all(struct queue *queue, queue_match_func_t function,
if (destroy)
destroy(tmp->data);
- queue_entry_unref(tmp);
+ free(tmp);
count++;
}
}
diff --git a/src/shared/queue.h b/src/shared/queue.h
index 3bc8d2e9..8cd817cc 100644
--- a/src/shared/queue.h
+++ b/src/shared/queue.h
@@ -28,7 +28,6 @@ typedef void (*queue_destroy_func_t)(void *data);
struct queue;
struct queue_entry {
- int ref_count;
void *data;
struct queue_entry *next;
};
diff --git a/src/shared/ringbuf.c b/src/shared/ringbuf.c
index a11d2dce..8e7c50e9 100644
--- a/src/shared/ringbuf.c
+++ b/src/shared/ringbuf.c
@@ -72,9 +72,6 @@ struct ringbuf *ringbuf_new(size_t size)
real_size = align_power2(size);
ringbuf = new0(struct ringbuf, 1);
- if (!ringbuf)
- return NULL;
-
ringbuf->buffer = malloc(real_size);
if (!ringbuf->buffer) {
free(ringbuf);
diff --git a/src/shared/tester.c b/src/shared/tester.c
index 3c3089f3..80d65110 100644
--- a/src/shared/tester.c
+++ b/src/shared/tester.c
@@ -35,6 +35,10 @@
#include <glib.h>
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
#include "src/shared/util.h"
#include "src/shared/tester.h"
@@ -211,12 +215,6 @@ void tester_add_full(const char *name, const void *test_data,
}
test = new0(struct test_case, 1);
- if (!test) {
- if (destroy)
- destroy(user_data);
- return;
- }
-
test->name = strdup(name);
test->result = TEST_RESULT_NOT_RUN;
test->stage = TEST_STAGE_INVALID;
@@ -339,6 +337,10 @@ static gboolean teardown_callback(gpointer user_data)
print_progress(test->name, COLOR_MAGENTA, "teardown");
test->teardown_func(test->test_data);
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_DO_ADDED_LEAK_CHECK;
+#endif
+
return FALSE;
}
@@ -676,9 +678,6 @@ void tester_wait(unsigned int seconds, tester_wait_func_t func,
test = test_current->data;
wait = new0(struct wait_data, 1);
- if (!wait)
- return;
-
wait->seconds = seconds;
wait->test = test;
wait->func = func;
@@ -692,7 +691,7 @@ void tester_wait(unsigned int seconds, tester_wait_func_t func,
static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
- static unsigned int __terminated = 0;
+ static bool terminated = false;
struct signalfd_siginfo si;
ssize_t result;
int fd;
@@ -711,10 +710,10 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
switch (si.ssi_signo) {
case SIGINT:
case SIGTERM:
- if (__terminated == 0)
+ if (!terminated)
g_main_loop_quit(main_loop);
- __terminated = 1;
+ terminated = true;
break;
}
diff --git a/src/shared/timeout-mainloop.c b/src/shared/timeout-mainloop.c
index f0993128..971124a2 100644
--- a/src/shared/timeout-mainloop.c
+++ b/src/shared/timeout-mainloop.c
@@ -58,9 +58,6 @@ unsigned int timeout_add(unsigned int timeout, timeout_func_t func,
struct timeout_data *data;
data = new0(struct timeout_data, 1);
- if (!data)
- return 0;
-
data->func = func;
data->user_data = user_data;
data->timeout = timeout;
diff --git a/src/shared/uhid.c b/src/shared/uhid.c
index f7ad0cb8..1c684cd9 100644
--- a/src/shared/uhid.c
+++ b/src/shared/uhid.c
@@ -125,16 +125,11 @@ struct bt_uhid *bt_uhid_new(int fd)
struct bt_uhid *uhid;
uhid = new0(struct bt_uhid, 1);
- if (!uhid)
- return NULL;
-
uhid->io = io_new(fd);
if (!uhid->io)
goto failed;
uhid->notify_list = queue_new();
- if (!uhid->notify_list)
- goto failed;
if (!io_set_read_handler(uhid->io, uhid_read_handler, uhid, NULL))
goto failed;
@@ -186,9 +181,6 @@ unsigned int bt_uhid_register(struct bt_uhid *uhid, uint32_t event,
return 0;
notify = new0(struct uhid_notify, 1);
- if (!notify)
- return 0;
-
notify->id = uhid->notify_id++;
notify->event = event;
notify->func = func;
diff --git a/src/shared/util.c b/src/shared/util.c
index a70c709a..78785523 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -37,6 +37,22 @@
#include "src/shared/util.h"
+void *btd_malloc(size_t size)
+{
+ if (__builtin_expect(!!size, 1)) {
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr)
+ return ptr;
+
+ fprintf(stderr, "failed to allocate %zu bytes\n", size);
+ abort();
+ }
+
+ return NULL;
+}
+
void util_debug(util_debug_func_t function, void *user_data,
const char *format, ...)
{
diff --git a/src/shared/util.h b/src/shared/util.h
index 30b7d923..ff705d00 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <alloca.h>
#include <byteswap.h>
+#include <string.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define le16_to_cpu(val) (val)
@@ -78,10 +79,21 @@ do { \
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
-#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+#define new0(type, count) \
+ (type *) (__extension__ ({ \
+ size_t __n = (size_t) (count); \
+ size_t __s = sizeof(type); \
+ void *__p; \
+ __p = btd_malloc(__n * __s); \
+ memset(__p, 0, __n * __s); \
+ __p; \
+ }))
+
#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
#define malloc0(n) (calloc((n), 1))
+void *btd_malloc(size_t size);
+
typedef void (*util_debug_func_t)(const char *str, void *user_data);
void util_debug(util_debug_func_t function, void *user_data,
@@ -96,6 +108,11 @@ unsigned char util_get_dt(const char *parent, const char *name);
uint8_t util_get_uid(unsigned int *bitmap, uint8_t max);
void util_clear_uid(unsigned int *bitmap, uint8_t id);
+static inline uint8_t get_u8(const void *ptr)
+{
+ return *((uint8_t *) ptr);
+}
+
static inline uint16_t get_le16(const void *ptr)
{
return le16_to_cpu(get_unaligned((const uint16_t *) ptr));
diff --git a/test/example-advertisement b/test/example-advertisement
new file mode 100644
index 00000000..ce6e40fc
--- /dev/null
+++ b/test/example-advertisement
@@ -0,0 +1,178 @@
+#!/usr/bin/python
+
+import dbus
+import dbus.exceptions
+import dbus.mainloop.glib
+import dbus.service
+
+import array
+import gobject
+
+from random import randint
+
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+LE_ADVERTISEMENT_IFACE = 'org.bluez.LEAdvertisement1'
+
+
+class InvalidArgsException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs'
+
+
+class NotSupportedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.NotSupported'
+
+
+class NotPermittedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.NotPermitted'
+
+
+class InvalidValueLengthException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.InvalidValueLength'
+
+
+class FailedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.Failed'
+
+
+class Advertisement(dbus.service.Object):
+ PATH_BASE = '/org/bluez/example/advertisement'
+
+ def __init__(self, bus, index, advertising_type):
+ self.path = self.PATH_BASE + str(index)
+ self.bus = bus
+ self.ad_type = advertising_type
+ self.service_uuids = None
+ self.manufacturer_data = None
+ self.solicit_uuids = None
+ self.service_data = None
+ self.include_tx_power = None
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ properties = dict()
+ properties['Type'] = self.ad_type
+ if self.service_uuids is not None:
+ properties['ServiceUUIDs'] = dbus.Array(self.service_uuids,
+ signature='s')
+ if self.solicit_uuids is not None:
+ properties['SolicitUUIDs'] = dbus.Array(self.solicit_uuids,
+ signature='s')
+ if self.manufacturer_data is not None:
+ properties['ManufacturerData'] = dbus.Dictionary(
+ self.manufacturer_data, signature='qay')
+ if self.service_data is not None:
+ properties['ServiceData'] = dbus.Dictionary(self.service_data,
+ signature='say')
+ if self.include_tx_power is not None:
+ properties['IncludeTxPower'] = dbus.Boolean(self.include_tx_power)
+ return {LE_ADVERTISEMENT_IFACE: properties}
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_service_uuid(self, uuid):
+ if not self.service_uuids:
+ self.service_uuids = []
+ self.service_uuids.append(uuid)
+
+ def add_solicit_uuid(self, uuid):
+ if not self.solicit_uuids:
+ self.solicit_uuids = []
+ self.solicit_uuids.append(uuid)
+
+ def add_manufacturer_data(self, manuf_code, data):
+ if not self.manufacturer_data:
+ self.manufacturer_data = dict()
+ self.manufacturer_data[manuf_code] = data
+
+ def add_service_data(self, uuid, data):
+ if not self.service_data:
+ self.service_data = dict()
+ self.service_data[uuid] = data
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ print 'GetAll'
+ if interface != LE_ADVERTISEMENT_IFACE:
+ raise InvalidArgsException()
+ print 'returning props'
+ return self.get_properties()[LE_ADVERTISEMENT_IFACE]
+
+ @dbus.service.method(LE_ADVERTISEMENT_IFACE,
+ in_signature='',
+ out_signature='')
+ def Release(self):
+ print '%s: Released!' % self.path
+
+class TestAdvertisement(Advertisement):
+
+ def __init__(self, bus, index):
+ Advertisement.__init__(self, bus, index, 'peripheral')
+ self.add_service_uuid('180D')
+ self.add_service_uuid('180F')
+ self.add_manufacturer_data(0xffff, [0x00, 0x01, 0x02, 0x03, 0x04])
+ self.add_service_data('9999', [0x00, 0x01, 0x02, 0x03, 0x04])
+ self.include_tx_power = True
+
+
+def register_ad_cb():
+ print 'Advertisement registered'
+
+
+def register_ad_error_cb(error):
+ print 'Failed to register advertisement: ' + str(error)
+ mainloop.quit()
+
+
+def find_adapter(bus):
+ remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
+ DBUS_OM_IFACE)
+ objects = remote_om.GetManagedObjects()
+
+ for o, props in objects.iteritems():
+ if LE_ADVERTISING_MANAGER_IFACE in props:
+ return o
+
+ return None
+
+
+def main():
+ global mainloop
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ adapter = find_adapter(bus)
+ if not adapter:
+ print 'LEAdvertisingManager1 interface not found'
+ return
+
+ adapter_props = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+ "org.freedesktop.DBus.Properties");
+
+ adapter_props.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(1))
+
+ ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+ LE_ADVERTISING_MANAGER_IFACE)
+
+ test_advertisement = TestAdvertisement(bus, 0)
+
+ mainloop = gobject.MainLoop()
+
+ ad_manager.RegisterAdvertisement(test_advertisement.get_path(), {},
+ reply_handler=register_ad_cb,
+ error_handler=register_ad_error_cb)
+
+ mainloop.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/test/example-gatt-client b/test/example-gatt-client
new file mode 100644
index 00000000..724a45d8
--- /dev/null
+++ b/test/example-gatt-client
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+
+import argparse
+import dbus
+import gobject
+import sys
+
+from dbus.mainloop.glib import DBusGMainLoop
+
+bus = None
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+GATT_SERVICE_IFACE = 'org.bluez.GattService1'
+GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
+
+HR_SVC_UUID = '0000180d-0000-1000-8000-00805f9b34fb'
+HR_MSRMT_UUID = '00002a37-0000-1000-8000-00805f9b34fb'
+BODY_SNSR_LOC_UUID = '00002a38-0000-1000-8000-00805f9b34fb'
+HR_CTRL_PT_UUID = '00002a39-0000-1000-8000-00805f9b34fb'
+
+# The objects that we interact with.
+hr_service = None
+hr_msrmt_chrc = None
+body_snsr_loc_chrc = None
+hr_ctrl_pt_chrc = None
+
+
+def generic_error_cb(error):
+ print('D-Bus call failed: ' + str(error))
+ mainloop.quit()
+
+
+def body_sensor_val_to_str(val):
+ if val == 0:
+ return 'Other'
+ if val == 1:
+ return 'Chest'
+ if val == 2:
+ return 'Wrist'
+ if val == 3:
+ return 'Finger'
+ if val == 4:
+ return 'Hand'
+ if val == 5:
+ return 'Ear Lobe'
+ if val == 6:
+ return 'Foot'
+
+ return 'Reserved value'
+
+
+def sensor_contact_val_to_str(val):
+ if val == 0 or val == 1:
+ return 'not supported'
+ if val == 2:
+ return 'no contact detected'
+ if val == 3:
+ return 'contact detected'
+
+ return 'invalid value'
+
+
+def body_sensor_val_cb(value):
+ if len(value) != 1:
+ print('Invalid body sensor location value: ' + repr(value))
+ return
+
+ print('Body sensor location value: ' + body_sensor_val_to_str(value[0]))
+
+
+def hr_msrmt_start_notify_cb():
+ print('HR Measurement notifications enabled')
+
+
+def hr_msrmt_changed_cb(iface, changed_props, invalidated_props):
+ if iface != GATT_CHRC_IFACE:
+ return
+
+ if not len(changed_props):
+ return
+
+ value = changed_props.get('Value', None)
+ if not value:
+ return
+
+ print('New HR Measurement')
+
+ flags = value[0]
+ value_format = flags & 0x01
+ sc_status = (flags >> 1) & 0x03
+ ee_status = flags & 0x08
+
+ if value_format == 0x00:
+ hr_msrmt = value[1]
+ next_ind = 2
+ else:
+ hr_msrmt = value[1] | (value[2] << 8)
+ next_ind = 3
+
+ print('\tHR: ' + str(int(hr_msrmt)))
+ print('\tSensor Contact status: ' +
+ sensor_contact_val_to_str(sc_status))
+
+ if ee_status:
+ print('\tEnergy Expended: ' + str(int(value[next_ind])))
+
+
+def start_client():
+ # Read the Body Sensor Location value and print it asynchronously.
+ body_snsr_loc_chrc[0].ReadValue(reply_handler=body_sensor_val_cb,
+ error_handler=generic_error_cb,
+ dbus_interface=GATT_CHRC_IFACE)
+
+ # Listen to PropertiesChanged signals from the Heart Measurement
+ # Characteristic.
+ hr_msrmt_prop_iface = dbus.Interface(hr_msrmt_chrc[0], DBUS_PROP_IFACE)
+ hr_msrmt_prop_iface.connect_to_signal("PropertiesChanged",
+ hr_msrmt_changed_cb)
+
+ # Subscribe to Heart Rate Measurement notifications.
+ hr_msrmt_chrc[0].StartNotify(reply_handler=hr_msrmt_start_notify_cb,
+ error_handler=generic_error_cb,
+ dbus_interface=GATT_CHRC_IFACE)
+
+
+def process_chrc(chrc_path):
+ chrc = bus.get_object(BLUEZ_SERVICE_NAME, chrc_path)
+ chrc_props = chrc.GetAll(GATT_CHRC_IFACE,
+ dbus_interface=DBUS_PROP_IFACE)
+
+ uuid = chrc_props['UUID']
+
+ if uuid == HR_MSRMT_UUID:
+ global hr_msrmt_chrc
+ hr_msrmt_chrc = (chrc, chrc_props)
+ elif uuid == BODY_SNSR_LOC_UUID:
+ global body_snsr_loc_chrc
+ body_snsr_loc_chrc = (chrc, chrc_props)
+ elif uuid == HR_CTRL_PT_UUID:
+ global hr_ctrl_pt_chrc
+ hr_ctrl_pt_chrc = (chrc, chrc_props)
+ else:
+ print('Unrecognized characteristic: ' + uuid)
+
+ return True
+
+
+def process_hr_service(service_path):
+ service = bus.get_object(BLUEZ_SERVICE_NAME, service_path)
+ service_props = service.GetAll(GATT_SERVICE_IFACE,
+ dbus_interface=DBUS_PROP_IFACE)
+
+ uuid = service_props['UUID']
+
+ if uuid != HR_SVC_UUID:
+ print('Service is not a Heart Rate Service: ' + uuid)
+ return False
+
+ # Process the characteristics.
+ chrc_paths = service_props['Characteristics']
+ for chrc_path in chrc_paths:
+ process_chrc(chrc_path)
+
+ global hr_service
+ hr_service = (service, service_props, service_path)
+
+ return True
+
+
+def interfaces_removed_cb(object_path, interfaces):
+ if not hr_service:
+ return
+
+ if object_path == hr_service[2]:
+ print('Service was removed')
+ mainloop.quit()
+
+
+def main():
+ # Prase the service path from the arguments.
+ parser = argparse.ArgumentParser(
+ description='D-Bus Heart Rate Service client example')
+ parser.add_argument('service_path', metavar='<service-path>',
+ type=dbus.ObjectPath, nargs=1,
+ help='GATT service object path')
+ args = parser.parse_args()
+ service_path = args.service_path[0]
+
+ # Set up the main loop.
+ DBusGMainLoop(set_as_default=True)
+ global bus
+ bus = dbus.SystemBus()
+ global mainloop
+ mainloop = gobject.MainLoop()
+
+ om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
+ om.connect_to_signal('InterfacesRemoved', interfaces_removed_cb)
+
+ try:
+ if not process_hr_service(service_path):
+ sys.exit(1)
+ except dbus.DBusException as e:
+ print e.message
+ sys.exit(1)
+
+ print 'Heart Rate Service ready'
+
+ start_client()
+
+ mainloop.run()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/example-gatt-server b/test/example-gatt-server
new file mode 100644
index 00000000..67dee1ad
--- /dev/null
+++ b/test/example-gatt-server
@@ -0,0 +1,591 @@
+#!/usr/bin/python
+
+import dbus
+import dbus.exceptions
+import dbus.mainloop.glib
+import dbus.service
+
+import array
+import gobject
+
+from random import randint
+from collections import OrderedDict
+
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+GATT_MANAGER_IFACE = 'org.bluez.GattManager1'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+GATT_SERVICE_IFACE = 'org.bluez.GattService1'
+GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
+GATT_DESC_IFACE = 'org.bluez.GattDescriptor1'
+
+class InvalidArgsException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs'
+
+class NotSupportedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.NotSupported'
+
+class NotPermittedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.NotPermitted'
+
+class InvalidValueLengthException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.InvalidValueLength'
+
+class FailedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.Failed'
+
+
+class Application(dbus.service.Object):
+ def __init__(self, bus):
+ self.path = '/'
+ self.services = []
+ dbus.service.Object.__init__(self, bus, self.path)
+ self.add_service(HeartRateService(bus, 0))
+ self.add_service(BatteryService(bus, 1))
+ self.add_service(TestService(bus, 2))
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_service(self, service):
+ self.services.append(service)
+
+ @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
+ def GetManagedObjects(self):
+ response = OrderedDict()
+ print('GetManagedObjects')
+
+ for service in self.services:
+ response[service.get_path()] = service.get_properties()
+ chrcs = service.get_characteristics()
+ for chrc in chrcs:
+ response[chrc.get_path()] = chrc.get_properties()
+ descs = chrc.get_descriptors()
+ for desc in descs:
+ response[desc.get_path()] = desc.get_properties()
+
+ return response
+
+
+class Service(dbus.service.Object):
+ PATH_BASE = '/org/bluez/example/service'
+
+ def __init__(self, bus, index, uuid, primary):
+ self.path = self.PATH_BASE + str(index)
+ self.bus = bus
+ self.uuid = uuid
+ self.primary = primary
+ self.characteristics = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ return {
+ GATT_SERVICE_IFACE: {
+ 'UUID': self.uuid,
+ 'Primary': self.primary,
+ 'Characteristics': dbus.Array(
+ self.get_characteristic_paths(),
+ signature='o')
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_characteristic(self, characteristic):
+ self.characteristics.append(characteristic)
+
+ def get_characteristic_paths(self):
+ result = []
+ for chrc in self.characteristics:
+ result.append(chrc.get_path())
+ return result
+
+ def get_characteristics(self):
+ return self.characteristics
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ if interface != GATT_SERVICE_IFACE:
+ raise InvalidArgsException()
+
+ return self.get_properties[GATT_SERVICE_IFACE]
+
+
+class Characteristic(dbus.service.Object):
+ def __init__(self, bus, index, uuid, flags, service):
+ self.path = service.path + '/char' + str(index)
+ self.bus = bus
+ self.uuid = uuid
+ self.service = service
+ self.flags = flags
+ self.descriptors = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ return {
+ GATT_CHRC_IFACE: {
+ 'Service': self.service.get_path(),
+ 'UUID': self.uuid,
+ 'Flags': self.flags,
+ 'Descriptors': dbus.Array(
+ self.get_descriptor_paths(),
+ signature='o')
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_descriptor(self, descriptor):
+ self.descriptors.append(descriptor)
+
+ def get_descriptor_paths(self):
+ result = []
+ for desc in self.descriptors:
+ result.append(desc.get_path())
+ return result
+
+ def get_descriptors(self):
+ return self.descriptors
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ if interface != GATT_CHRC_IFACE:
+ raise InvalidArgsException()
+
+ return self.get_properties[GATT_CHRC_IFACE]
+
+ @dbus.service.method(GATT_CHRC_IFACE, out_signature='ay')
+ def ReadValue(self):
+ print('Default ReadValue called, returning error')
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_CHRC_IFACE, in_signature='ay')
+ def WriteValue(self, value):
+ print('Default WriteValue called, returning error')
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_CHRC_IFACE)
+ def StartNotify(self):
+ print('Default StartNotify called, returning error')
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_CHRC_IFACE)
+ def StopNotify(self):
+ print('Default StopNotify called, returning error')
+ raise NotSupportedException()
+
+ @dbus.service.signal(DBUS_PROP_IFACE,
+ signature='sa{sv}as')
+ def PropertiesChanged(self, interface, changed, invalidated):
+ pass
+
+
+class Descriptor(dbus.service.Object):
+ def __init__(self, bus, index, uuid, flags, characteristic):
+ self.path = characteristic.path + '/desc' + str(index)
+ self.bus = bus
+ self.uuid = uuid
+ self.flags = flags
+ self.chrc = characteristic
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ return {
+ GATT_DESC_IFACE: {
+ 'Characteristic': self.chrc.get_path(),
+ 'UUID': self.uuid,
+ 'Flags': self.flags,
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ if interface != GATT_DESC_IFACE:
+ raise InvalidArgsException()
+
+ return self.get_properties[GATT_CHRC_IFACE]
+
+ @dbus.service.method(GATT_DESC_IFACE, out_signature='ay')
+ def ReadValue(self):
+ print ('Default ReadValue called, returning error')
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_DESC_IFACE, in_signature='ay')
+ def WriteValue(self, value):
+ print('Default WriteValue called, returning error')
+ raise NotSupportedException()
+
+
+class HeartRateService(Service):
+ """
+ Fake Heart Rate Service that simulates a fake heart beat and control point
+ behavior.
+
+ """
+ HR_UUID = '0000180d-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index):
+ Service.__init__(self, bus, index, self.HR_UUID, True)
+ self.add_characteristic(HeartRateMeasurementChrc(bus, 0, self))
+ self.add_characteristic(BodySensorLocationChrc(bus, 1, self))
+ self.add_characteristic(HeartRateControlPointChrc(bus, 2, self))
+ self.energy_expended = 0
+
+
+class HeartRateMeasurementChrc(Characteristic):
+ HR_MSRMT_UUID = '00002a37-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.HR_MSRMT_UUID,
+ ['notify'],
+ service)
+ self.notifying = False
+ self.hr_ee_count = 0
+
+ def hr_msrmt_cb(self):
+ value = []
+ value.append(dbus.Byte(0x06))
+
+ value.append(dbus.Byte(randint(90, 130)))
+
+ if self.hr_ee_count % 10 == 0:
+ value[0] = dbus.Byte(value[0] | 0x08)
+ value.append(dbus.Byte(self.service.energy_expended & 0xff))
+ value.append(dbus.Byte((self.service.energy_expended >> 8) & 0xff))
+
+ self.service.energy_expended = \
+ min(0xffff, self.service.energy_expended + 1)
+ self.hr_ee_count += 1
+
+ print('Updating value: ' + repr(value))
+
+ self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': value }, [])
+
+ return self.notifying
+
+ def _update_hr_msrmt_simulation(self):
+ print('Update HR Measurement Simulation')
+
+ if not self.notifying:
+ return
+
+ gobject.timeout_add(1000, self.hr_msrmt_cb)
+
+ def StartNotify(self):
+ if self.notifying:
+ print('Already notifying, nothing to do')
+ return
+
+ self.notifying = True
+ self._update_hr_msrmt_simulation()
+
+ def StopNotify(self):
+ if not self.notifying:
+ print('Not notifying, nothing to do')
+ return
+
+ self.notifying = False
+ self._update_hr_msrmt_simulation()
+
+
+class BodySensorLocationChrc(Characteristic):
+ BODY_SNSR_LOC_UUID = '00002a38-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.BODY_SNSR_LOC_UUID,
+ ['read'],
+ service)
+
+ def ReadValue(self):
+ # Return 'Chest' as the sensor location.
+ return [ 0x01 ]
+
+class HeartRateControlPointChrc(Characteristic):
+ HR_CTRL_PT_UUID = '00002a39-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.HR_CTRL_PT_UUID,
+ ['write'],
+ service)
+
+ def WriteValue(self, value):
+ print('Heart Rate Control Point WriteValue called')
+
+ if len(value) != 1:
+ raise InvalidValueLengthException()
+
+ byte = value[0]
+ print('Control Point value: ' + repr(byte))
+
+ if byte != 1:
+ raise FailedException("0x80")
+
+ print('Energy Expended field reset!')
+ self.service.energy_expended = 0
+
+
+class BatteryService(Service):
+ """
+ Fake Battery service that emulates a draining battery.
+
+ """
+ BATTERY_UUID = '180f'
+
+ def __init__(self, bus, index):
+ Service.__init__(self, bus, index, self.BATTERY_UUID, True)
+ self.add_characteristic(BatteryLevelCharacteristic(bus, 0, self))
+
+
+class BatteryLevelCharacteristic(Characteristic):
+ """
+ Fake Battery Level characteristic. The battery level is drained by 2 points
+ every 5 seconds.
+
+ """
+ BATTERY_LVL_UUID = '2a19'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.BATTERY_LVL_UUID,
+ ['read', 'notify'],
+ service)
+ self.notifying = False
+ self.battery_lvl = 100
+ gobject.timeout_add(5000, self.drain_battery)
+
+ def notify_battery_level(self):
+ if not self.notifying:
+ return
+ self.PropertiesChanged(
+ GATT_CHRC_IFACE,
+ { 'Value': [dbus.Byte(self.battery_lvl)] }, [])
+
+ def drain_battery(self):
+ if self.battery_lvl > 0:
+ self.battery_lvl -= 2
+ if self.battery_lvl < 0:
+ self.battery_lvl = 0
+ print('Battery Level drained: ' + repr(self.battery_lvl))
+ self.notify_battery_level()
+ return True
+
+ def ReadValue(self):
+ print('Battery Level read: ' + repr(self.battery_lvl))
+ return [dbus.Byte(self.battery_lvl)]
+
+ def StartNotify(self):
+ if self.notifying:
+ print('Already notifying, nothing to do')
+ return
+
+ self.notifying = True
+ self.notify_battery_level()
+
+ def StopNotify(self):
+ if not self.notifying:
+ print('Not notifying, nothing to do')
+ return
+
+ self.notifying = False
+
+
+class TestService(Service):
+ """
+ Dummy test service that provides characteristics and descriptors that
+ exercise various API functionality.
+
+ """
+ TEST_SVC_UUID = '12345678-1234-5678-1234-56789abcdef0'
+
+ def __init__(self, bus, index):
+ Service.__init__(self, bus, index, self.TEST_SVC_UUID, False)
+ self.add_characteristic(TestCharacteristic(bus, 0, self))
+ self.add_characteristic(TestEncryptCharacteristic(bus, 1, self))
+
+class TestCharacteristic(Characteristic):
+ """
+ Dummy test characteristic. Allows writing arbitrary bytes to its value, and
+ contains "extended properties", as well as a test descriptor.
+
+ """
+ TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef1'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.TEST_CHRC_UUID,
+ ['read', 'write', 'writable-auxiliaries'],
+ service)
+ self.value = []
+ self.add_descriptor(TestDescriptor(bus, 0, self))
+ self.add_descriptor(
+ CharacteristicUserDescriptionDescriptor(bus, 1, self))
+
+ def ReadValue(self):
+ print('TestCharacteristic Read: ' + repr(self.value))
+ return self.value
+
+ def WriteValue(self, value):
+ print('TestCharacteristic Write: ' + repr(value))
+ self.value = value
+
+
+class TestDescriptor(Descriptor):
+ """
+ Dummy test descriptor. Returns a static value.
+
+ """
+ TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef2'
+
+ def __init__(self, bus, index, characteristic):
+ Descriptor.__init__(
+ self, bus, index,
+ self.TEST_DESC_UUID,
+ ['read', 'write'],
+ characteristic)
+
+ def ReadValue(self):
+ return [
+ dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t')
+ ]
+
+
+class CharacteristicUserDescriptionDescriptor(Descriptor):
+ """
+ Writable CUD descriptor.
+
+ """
+ CUD_UUID = '2901'
+
+ def __init__(self, bus, index, characteristic):
+ self.writable = 'writable-auxiliaries' in characteristic.flags
+ self.value = array.array('B', 'This is a characteristic for testing')
+ self.value = self.value.tolist()
+ Descriptor.__init__(
+ self, bus, index,
+ self.CUD_UUID,
+ ['read', 'write'],
+ characteristic)
+
+ def ReadValue(self):
+ return self.value
+
+ def WriteValue(self, value):
+ if not self.writable:
+ raise NotPermittedException()
+ self.value = value
+
+class TestEncryptCharacteristic(Characteristic):
+ """
+ Dummy test characteristic requiring encryption.
+
+ """
+ TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef3'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.TEST_CHRC_UUID,
+ ['encrypt-read', 'encrypt-write'],
+ service)
+ self.value = []
+ self.add_descriptor(TestEncryptDescriptor(bus, 2, self))
+ self.add_descriptor(
+ CharacteristicUserDescriptionDescriptor(bus, 3, self))
+
+ def ReadValue(self):
+ print('TestCharacteristic Read: ' + repr(self.value))
+ return self.value
+
+ def WriteValue(self, value):
+ print('TestCharacteristic Write: ' + repr(value))
+ self.value = value
+
+class TestEncryptDescriptor(Descriptor):
+ """
+ Dummy test descriptor requiring encryption. Returns a static value.
+
+ """
+ TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef4'
+
+ def __init__(self, bus, index, characteristic):
+ Descriptor.__init__(
+ self, bus, index,
+ self.TEST_DESC_UUID,
+ ['encrypt-read', 'encrypt-write'],
+ characteristic)
+
+ def ReadValue(self):
+ return [
+ dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t')
+ ]
+
+def register_app_cb():
+ print('GATT application registered')
+
+
+def register_app_error_cb(error):
+ print('Failed to register application: ' + str(error))
+ mainloop.quit()
+
+
+def find_adapter(bus):
+ remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
+ DBUS_OM_IFACE)
+ objects = remote_om.GetManagedObjects()
+
+ for o, props in objects.iteritems():
+ if props.has_key(GATT_MANAGER_IFACE):
+ return o
+
+ return None
+
+def main():
+ global mainloop
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ adapter = find_adapter(bus)
+ if not adapter:
+ print('GattManager1 interface not found')
+ return
+
+ service_manager = dbus.Interface(
+ bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+ GATT_MANAGER_IFACE)
+
+ app = Application(bus)
+
+ mainloop = gobject.MainLoop()
+
+ service_manager.RegisterApplication(app.get_path(), {},
+ reply_handler=register_app_cb,
+ error_handler=register_app_error_cb)
+
+ mainloop.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/test/exchange-business-cards b/test/exchange-business-cards
index 6805cf71..6805cf71 100755..100644
--- a/test/exchange-business-cards
+++ b/test/exchange-business-cards
diff --git a/test/ftp-client b/test/ftp-client
index 78c32b3f..4540602a 100755..100644
--- a/test/ftp-client
+++ b/test/ftp-client
@@ -77,16 +77,18 @@ class FtpClient:
if path != self.transfer_path:
return
- if properties['Status'] == 'complete' or \
- properties['Status'] == 'error':
+ if "Status" in properties and \
+ (properties['Status'] == 'complete' or \
+ properties['Status'] == 'error'):
if self.verbose:
print("Transfer %s" % properties['Status'])
mainloop.quit()
return
- if properties["Transferred"] == None:
+ if "Transferred" not in properties:
return
+ value = properties["Transferred"]
speed = (value - self.transferred) / 1000
print("Transfer progress %d/%d at %d kBps" % (value,
self.transfer_size,
diff --git a/test/get-managed-objects b/test/get-managed-objects
index 3156f658..3156f658 100755..100644
--- a/test/get-managed-objects
+++ b/test/get-managed-objects
diff --git a/test/get-obex-capabilities b/test/get-obex-capabilities
index e8afbad2..e8afbad2 100755..100644
--- a/test/get-obex-capabilities
+++ b/test/get-obex-capabilities
diff --git a/test/list-devices b/test/list-devices
index 0aac217d..0aac217d 100755..100644
--- a/test/list-devices
+++ b/test/list-devices
diff --git a/test/list-folders b/test/list-folders
index 7321a152..7321a152 100755..100644
--- a/test/list-folders
+++ b/test/list-folders
diff --git a/test/map-client b/test/map-client
index b9695da6..b9695da6 100755..100644
--- a/test/map-client
+++ b/test/map-client
diff --git a/test/monitor-bluetooth b/test/monitor-bluetooth
index d9b5472f..d9b5472f 100755..100644
--- a/test/monitor-bluetooth
+++ b/test/monitor-bluetooth
diff --git a/test/opp-client b/test/opp-client
index 62d5b845..62d5b845 100755..100644
--- a/test/opp-client
+++ b/test/opp-client
diff --git a/test/simple-agent b/test/simple-agent
index a69299a3..a69299a3 100755..100644
--- a/test/simple-agent
+++ b/test/simple-agent
diff --git a/test/simple-endpoint b/test/simple-endpoint
index 0164cff9..0164cff9 100755..100644
--- a/test/simple-endpoint
+++ b/test/simple-endpoint
diff --git a/test/simple-obex-agent b/test/simple-obex-agent
index 05ec4eda..05ec4eda 100755..100644
--- a/test/simple-obex-agent
+++ b/test/simple-obex-agent
diff --git a/test/simple-player b/test/simple-player
index a8ae0b1c..02754c2f 100755..100644
--- a/test/simple-player
+++ b/test/simple-player
@@ -43,6 +43,7 @@ class Player(dbus.service.Object):
self.properties = dbus.Dictionary({
"PlaybackStatus" : "playing",
+ "Identity" : "SimplePlayer",
"LoopStatus" : "None",
"Rate" : dbus.Double(1.0),
"Shuffle" : dbus.Boolean(False),
diff --git a/test/test-adapter b/test/test-adapter
index 959a4370..959a4370 100755..100644
--- a/test/test-adapter
+++ b/test/test-adapter
diff --git a/test/test-alert b/test/test-alert
index 43b3cf36..43b3cf36 100755..100644
--- a/test/test-alert
+++ b/test/test-alert
diff --git a/test/test-cyclingspeed b/test/test-cyclingspeed
index 393f79c7..393f79c7 100755..100644
--- a/test/test-cyclingspeed
+++ b/test/test-cyclingspeed
diff --git a/test/test-device b/test/test-device
index b490d53f..b490d53f 100755..100644
--- a/test/test-device
+++ b/test/test-device
diff --git a/test/test-discovery b/test/test-discovery
index 73b81611..cea77683 100755..100644
--- a/test/test-discovery
+++ b/test/test-discovery
@@ -107,10 +107,6 @@ def properties_changed(interface, changed, invalidated, path):
else:
print_normal(address, devices[path])
-def property_changed(name, value):
- if (name == "Discovering" and not value):
- mainloop.quit()
-
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -119,6 +115,18 @@ if __name__ == '__main__':
option_list = [
make_option("-i", "--device", action="store",
type="string", dest="dev_id"),
+ make_option("-u", "--uuids", action="store",
+ type="string", dest="uuids",
+ help="Filtered service UUIDs [uuid1,uuid2,...]"),
+ make_option("-r", "--rssi", action="store",
+ type="int", dest="rssi",
+ help="RSSI threshold value"),
+ make_option("-p", "--pathloss", action="store",
+ type="int", dest="pathloss",
+ help="Pathloss threshold value"),
+ make_option("-t", "--transport", action="store",
+ type="string", dest="transport",
+ help="Type of scan to run (le/bredr/auto)"),
make_option("-c", "--compact",
action="store_true", dest="compact"),
]
@@ -141,10 +149,6 @@ if __name__ == '__main__':
arg0 = "org.bluez.Device1",
path_keyword = "path")
- bus.add_signal_receiver(property_changed,
- dbus_interface = "org.bluez.Adapter1",
- signal_name = "PropertyChanged")
-
om = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.freedesktop.DBus.ObjectManager")
objects = om.GetManagedObjects()
@@ -152,6 +156,26 @@ if __name__ == '__main__':
if "org.bluez.Device1" in interfaces:
devices[path] = interfaces["org.bluez.Device1"]
+ scan_filter = dict()
+
+ if options.uuids:
+ uuids = []
+ uuid_list = options.uuids.split(',')
+ for uuid in uuid_list:
+ uuids.append(uuid)
+
+ scan_filter.update({ "UUIDs": uuids })
+
+ if options.rssi:
+ scan_filter.update({ "RSSI": dbus.Int16(options.rssi) })
+
+ if options.pathloss:
+ scan_filter.update({ "Pathloss": dbus.UInt16(options.pathloss) })
+
+ if options.transport:
+ scan_filter.update({ "Transport": options.transport })
+
+ adapter.SetDiscoveryFilter(scan_filter)
adapter.StartDiscovery()
mainloop = GObject.MainLoop()
diff --git a/test/test-gatt-profile b/test/test-gatt-profile
new file mode 100644
index 00000000..ad320b1b
--- /dev/null
+++ b/test/test-gatt-profile
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from optparse import OptionParser, make_option
+import os
+import sys
+import uuid
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+import bluezutils
+
+class GattProfile(dbus.service.Object):
+ @dbus.service.method("org.bluez.GattProfile1",
+ in_signature="", out_signature="")
+ def Release(self):
+ print("Release")
+ mainloop.quit()
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ path = bluezutils.find_adapter().object_path
+
+ manager = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.GattManager1")
+
+ option_list = [
+ make_option("-u", "--uuid", action="store",
+ type="string", dest="uuid",
+ default=None),
+ make_option("-p", "--path", action="store",
+ type="string", dest="path",
+ default="/foo/bar/profile"),
+ ]
+
+ opts = dbus.Dictionary({ }, signature='sv')
+
+ parser = OptionParser(option_list=option_list)
+
+ (options, args) = parser.parse_args()
+
+ profile = GattProfile(bus, options.path)
+
+ mainloop = GObject.MainLoop()
+
+ if not options.uuid:
+ options.uuid = str(uuid.uuid4())
+
+ uuids = { options.uuid }
+ manager.RegisterProfile(options.path, uuids, opts)
+
+ mainloop.run()
diff --git a/test/test-health b/test/test-health
index 24afa799..24afa799 100755..100644
--- a/test/test-health
+++ b/test/test-health
diff --git a/test/test-health-sink b/test/test-health-sink
index 37e630a2..37e630a2 100755..100644
--- a/test/test-health-sink
+++ b/test/test-health-sink
diff --git a/test/test-heartrate b/test/test-heartrate
index 5e4e7e5c..5e4e7e5c 100755..100644
--- a/test/test-heartrate
+++ b/test/test-heartrate
diff --git a/test/test-hfp b/test/test-hfp
index a8060439..a8060439 100755..100644
--- a/test/test-hfp
+++ b/test/test-hfp
diff --git a/test/test-manager b/test/test-manager
index 4f5994f6..4f5994f6 100755..100644
--- a/test/test-manager
+++ b/test/test-manager
diff --git a/test/test-nap b/test/test-nap
index 00a2585a..ab67a750 100755..100644
--- a/test/test-nap
+++ b/test/test-nap
@@ -7,6 +7,11 @@ import sys
import time
import dbus
import bluezutils
+import dbus.mainloop.glib
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
bus = dbus.SystemBus()
@@ -29,16 +34,14 @@ if (len(args) < 1):
else:
bridge = args[0]
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+mainloop = GObject.MainLoop()
+
server.Register(service, bridge)
print("Server for %s registered for %s" % (service, bridge))
print("Press CTRL-C to disconnect")
-try:
- time.sleep(1000)
- print("Terminating connection")
-except:
- pass
-
-server.Unregister(service)
+mainloop.run()
diff --git a/test/test-network b/test/test-network
index 6f094864..6f094864 100755..100644
--- a/test/test-network
+++ b/test/test-network
diff --git a/test/test-profile b/test/test-profile
index 27915806..27915806 100755..100644
--- a/test/test-profile
+++ b/test/test-profile
diff --git a/test/test-proximity b/test/test-proximity
index 66b7bc24..66b7bc24 100755..100644
--- a/test/test-proximity
+++ b/test/test-proximity
diff --git a/test/test-sap-server b/test/test-sap-server
index ff178af2..ff178af2 100755..100644
--- a/test/test-sap-server
+++ b/test/test-sap-server
diff --git a/test/test-thermometer b/test/test-thermometer
index 7e67c234..7e67c234 100755..100644
--- a/test/test-thermometer
+++ b/test/test-thermometer
diff --git a/tools/avinfo.c b/tools/avinfo.c
index 3f406ca1..31c4e106 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -74,6 +74,10 @@
#define AVDTP_MEDIA_TYPE_VIDEO 0x01
#define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02
+/* Content Protection types definitions */
+#define AVDTP_CONTENT_PROTECTION_TYPE_DTCP 0x0001
+#define AVDTP_CONTENT_PROTECTION_TYPE_SCMS_T 0x0002
+
struct avdtp_service_capability {
uint8_t category;
uint8_t length;
@@ -158,6 +162,11 @@ struct getcap_resp {
uint8_t caps[0];
} __attribute__ ((packed));
+struct avdtp_content_protection_capability {
+ uint16_t content_protection_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
static void print_aptx(a2dp_aptx_t *aptx)
{
printf("\t\tVendor Specific Value (aptX)");
@@ -181,6 +190,16 @@ static void print_aptx(a2dp_aptx_t *aptx)
printf("\n");
}
+static void print_ldac(a2dp_ldac_t *ldac)
+{
+ printf("\t\tVendor Specific Value (LDAC)");
+
+ printf("\n\t\t\tUnknown: %02x %02x", ldac->unknown[0],
+ ldac->unknown[1]);
+
+ printf("\n");
+}
+
static void print_vendor(a2dp_vendor_codec_t *vendor)
{
uint32_t vendor_id = btohl(vendor->vendor_id);
@@ -194,6 +213,8 @@ static void print_vendor(a2dp_vendor_codec_t *vendor)
if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
print_aptx((void *) vendor);
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ print_ldac((void *) vendor);
}
static void print_mpeg24(a2dp_aac_t *aac)
@@ -393,6 +414,25 @@ static void print_media_codec(struct avdtp_media_codec_capability *cap)
}
}
+static void print_content_protection(
+ struct avdtp_content_protection_capability *cap)
+{
+ printf("\tContent Protection: ");
+
+ switch (btohs(cap->content_protection_type)) {
+ case AVDTP_CONTENT_PROTECTION_TYPE_DTCP:
+ printf("DTCP");
+ break;
+ case AVDTP_CONTENT_PROTECTION_TYPE_SCMS_T:
+ printf("SCMS-T");
+ break;
+ default:
+ printf("Unknown");
+ }
+
+ printf("\n");
+}
+
static void print_caps(void *data, int size)
{
int processed;
@@ -411,13 +451,15 @@ static void print_caps(void *data, int size)
case AVDTP_MEDIA_TRANSPORT:
case AVDTP_REPORTING:
case AVDTP_RECOVERY:
- case AVDTP_CONTENT_PROTECTION:
case AVDTP_MULTIPLEXING:
/* FIXME: Add proper functions */
break;
case AVDTP_MEDIA_CODEC:
print_media_codec((void *) cap->data);
break;
+ case AVDTP_CONTENT_PROTECTION:
+ print_content_protection((void *) cap->data);
+ break;
}
processed += 2 + cap->length;
diff --git a/tools/bccmd.c b/tools/bccmd.c
index 7cce4261..4d15f3f4 100644
--- a/tools/bccmd.c
+++ b/tools/bccmd.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <getopt.h>
#include <sys/socket.h>
+#include <unistd.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
@@ -1040,6 +1041,47 @@ static int cmd_pscheck(int transport, int argc, char *argv[])
return 0;
}
+static int cmd_adc(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t mux, value;
+ int err;
+
+ OPT_HELP(1, NULL);
+
+ if (!strncasecmp(argv[0], "0x", 2))
+ mux = strtol(argv[0], NULL, 16);
+ else
+ mux = atoi(argv[0]);
+
+ /* Request an ADC read from a particular mux'ed input */
+ memset(array, 0, sizeof(array));
+ array[0] = mux & 0xff;
+ array[1] = mux >> 8;
+
+ err = transport_write(transport, CSR_VARID_ADC, array, 2);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ /* have to wait a short while, then read result */
+ usleep(50000);
+ err = transport_read(transport, CSR_VARID_ADC_RES, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ mux = array[0] | (array[1] << 8);
+ value = array[4] | (array[5] << 8);
+
+ printf("ADC value from Mux 0x%02x : 0x%04x (%s)\n", mux, value,
+ array[2] == 1 ? "valid" : "invalid");
+
+ return 0;
+}
+
static struct {
char *str;
int (*func)(int transport, int argc, char *argv[]);
@@ -1070,6 +1112,7 @@ static struct {
{ "psread", cmd_psread, NULL, "Read all PS keys" },
{ "psload", cmd_psload, "<file>", "Load all PS keys from PSR file" },
{ "pscheck", cmd_pscheck, "<file>", "Check PSR file" },
+ { "adc", cmd_adc, "<mux>", "Read ADC value of <mux> input" },
{ NULL }
};
diff --git a/tools/bnep-tester.c b/tools/bnep-tester.c
new file mode 100644
index 00000000..ec4ad266
--- /dev/null
+++ b/tools/bnep-tester.c
@@ -0,0 +1,309 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/bnep.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+#include "emulator/hciemu.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+
+struct test_data {
+ struct mgmt *mgmt;
+ uint16_t mgmt_index;
+ struct hciemu *hciemu;
+ enum hciemu_type hciemu_type;
+ const void *test_data;
+ unsigned int io_id;
+ uint16_t conn_handle;
+};
+
+struct rfcomm_client_data {
+ uint8_t server_channel;
+ uint8_t client_channel;
+ int expected_connect_err;
+ const uint8_t *send_data;
+ const uint8_t *read_data;
+ uint16_t data_len;
+};
+
+struct rfcomm_server_data {
+ uint8_t server_channel;
+ uint8_t client_channel;
+ bool expected_status;
+ const uint8_t *send_data;
+ const uint8_t *read_data;
+ uint16_t data_len;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct mgmt_rp_read_info *rp = param;
+ char addr[18];
+ uint16_t manufacturer;
+ uint32_t supported_settings, current_settings;
+
+ tester_print("Read Info callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ ba2str(&rp->bdaddr, addr);
+ manufacturer = btohs(rp->manufacturer);
+ supported_settings = btohl(rp->supported_settings);
+ current_settings = btohl(rp->current_settings);
+
+ tester_print(" Address: %s", addr);
+ tester_print(" Version: 0x%02x", rp->version);
+ tester_print(" Manufacturer: 0x%04x", manufacturer);
+ tester_print(" Supported settings: 0x%08x", supported_settings);
+ tester_print(" Current settings: 0x%08x", current_settings);
+ tester_print(" Class: 0x%02x%02x%02x",
+ rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+ tester_print(" Name: %s", rp->name);
+ tester_print(" Short name: %s", rp->short_name);
+
+ if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Index Added callback");
+ tester_print(" Index: 0x%04x", index);
+
+ data->mgmt_index = index;
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+ read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Index Removed callback");
+ tester_print(" Index: 0x%04x", index);
+
+ if (index != data->mgmt_index)
+ return;
+
+ mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+ mgmt_unref(data->mgmt);
+ data->mgmt = NULL;
+
+ tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Read Index List callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+ index_added_callback, NULL, NULL);
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+ index_removed_callback, NULL, NULL);
+
+ data->hciemu = hciemu_new(data->hciemu_type);
+ if (!data->hciemu) {
+ tester_warn("Failed to setup HCI emulation");
+ tester_pre_setup_failed();
+ }
+
+ tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ data->mgmt = mgmt_new_default();
+ if (!data->mgmt) {
+ tester_warn("Failed to setup management interface");
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (tester_use_debug())
+ mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+ read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ if (data->io_id > 0) {
+ g_source_remove(data->io_id);
+ data->io_id = 0;
+ }
+
+ hciemu_unref(data->hciemu);
+ data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+ struct test_data *data = test_data;
+
+ free(data);
+}
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+ const void *param, uint8_t len,
+ void *user_data)
+{
+ switch (opcode) {
+ case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+ break;
+ default:
+ return;
+ }
+
+ tester_print("Client set connectable status 0x%02x", status);
+
+ if (status)
+ tester_setup_failed();
+ else
+ tester_setup_complete();
+}
+
+static void setup_powered_client_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bthost *bthost;
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Controller powered on");
+
+ bthost = hciemu_client_get_host(data->hciemu);
+ bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
+ bthost_write_scan_enable(bthost, 0x03);
+}
+
+static void setup_powered_client(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Powering on controller");
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), param, setup_powered_client_callback,
+ NULL, NULL);
+}
+
+static void test_basic(const void *test_data)
+{
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
+ if (sk < 0) {
+ tester_warn("Can't create socket: %s (%d)", strerror(errno),
+ errno);
+ tester_test_failed();
+ return;
+ }
+
+ close(sk);
+
+ tester_test_passed();
+}
+
+#define test_bnep(name, data, setup, func) \
+ do { \
+ struct test_data *user; \
+ user = malloc(sizeof(struct test_data)); \
+ if (!user) \
+ break; \
+ user->hciemu_type = HCIEMU_TYPE_BREDR; \
+ user->test_data = data; \
+ user->io_id = 0; \
+ tester_add_full(name, data, \
+ test_pre_setup, setup, func, NULL, \
+ test_post_teardown, 2, user, test_data_free); \
+ } while (0)
+
+int main(int argc, char *argv[])
+{
+ tester_init(&argc, &argv);
+
+ test_bnep("Basic BNEP Socket - Success", NULL,
+ setup_powered_client, test_basic);
+
+ return tester_run();
+}
diff --git a/tools/bneptest.c b/tools/bneptest.c
index 84319b9e..15d28faa 100644
--- a/tools/bneptest.c
+++ b/tools/bneptest.c
@@ -38,12 +38,12 @@
#include <netinet/in.h>
#include <linux/if_bridge.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
#include <glib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
#include "src/log.h"
#include "src/shared/util.h"
#include "btio/btio.h"
@@ -89,7 +89,7 @@ static int set_forward_delay(int sk)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
ifr.ifr_data = (char *) args;
if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0) {
diff --git a/tools/btattach.1 b/tools/btattach.1
new file mode 100644
index 00000000..ffd653d2
--- /dev/null
+++ b/tools/btattach.1
@@ -0,0 +1,53 @@
+.TH "btattach" "1" "November 2015" "BlueZ" "Linux System Administration"
+.SH NAME
+btattach \- attach serial devices to BlueZ stack
+
+.SH SYNOPSIS
+.B btattach
+.RB [\| \-B
+.IR device \|]
+.RB [\| \-A
+.IR device \|]
+.RB [\| \-P
+.IR protocol \|]
+.RB [\| \-R \|]
+
+.SH DESCRIPTION
+.LP
+btattach is used to attach a serial UART to the Bluetooth stack as a
+transport interface.
+
+.SH OPTIONS
+.TP
+.BI \-B " device" , " " \--bredr " device"
+Attach a BR/EDR controller.
+.TP
+.BI \-A " device" , " " \--amp " device"
+Attach an AMP controller.
+.TP
+.BI \-P " protocol" , " " \--protocol " protocol"
+Specify the protocol type for talking to the device.
+Supported values are:
+.RS
+.IP \(bu 2
+.B h4
+.IP \(bu 2
+.B bcsp
+.IP \(bu 2
+.B 3wire
+.IP \(bu 2
+.B h4ds
+.IP \(bu 2
+.B ll
+.IP \(bu 2
+.B ath3k
+.IP \(bu 2
+.B intel
+.IP \(bu 2
+.B bcm
+.IP \(bu 2
+.B qca
+.RE
+.TP
+.B \-R
+Set the device into raw mode (the kernel and bluetoothd will ignore it).
diff --git a/tools/btattach.c b/tools/btattach.c
index b7948a36..a025bb07 100644
--- a/tools/btattach.c
+++ b/tools/btattach.c
@@ -154,7 +154,8 @@ static int attach_proto(const char *path, unsigned int proto,
}
bt_hci_send(hci, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
- local_version_callback, NULL, NULL);
+ local_version_callback, hci,
+ (bt_hci_destroy_func_t) bt_hci_unref);
}
return fd;
@@ -187,28 +188,46 @@ static void usage(void)
printf("options:\n"
"\t-B, --bredr <device> Attach BR/EDR controller\n"
"\t-A, --amp <device> Attach AMP controller\n"
+ "\t-P, --protocol <proto> Specify protocol type\n"
"\t-h, --help Show help options\n");
}
static const struct option main_options[] = {
- { "bredr", required_argument, NULL, 'B' },
- { "amp", required_argument, NULL, 'A' },
- { "version", no_argument, NULL, 'v' },
- { "help", no_argument, NULL, 'h' },
+ { "bredr", required_argument, NULL, 'B' },
+ { "amp", required_argument, NULL, 'A' },
+ { "protocol", required_argument, NULL, 'P' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
+static const struct {
+ const char *name;
+ unsigned int id;
+} proto_table[] = {
+ { "h4", HCI_UART_H4 },
+ { "bcsp", HCI_UART_BCSP },
+ { "3wire", HCI_UART_3WIRE },
+ { "h4ds", HCI_UART_H4DS },
+ { "ll", HCI_UART_LL },
+ { "ath3k", HCI_UART_ATH3K },
+ { "intel", HCI_UART_INTEL },
+ { "bcm", HCI_UART_BCM },
+ { "qca", HCI_UART_QCA },
{ }
};
int main(int argc, char *argv[])
{
- const char *bredr_path = NULL, *amp_path = NULL;
+ const char *bredr_path = NULL, *amp_path = NULL, *proto = NULL;
bool raw_device = false;
sigset_t mask;
- int exit_status, count = 0;
+ int exit_status, count = 0, proto_id = HCI_UART_H4;
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "B:A:Rvh",
+ opt = getopt_long(argc, argv, "B:A:P:Rvh",
main_options, NULL);
if (opt < 0)
break;
@@ -220,6 +239,9 @@ int main(int argc, char *argv[])
case 'A':
amp_path = optarg;
break;
+ case 'P':
+ proto = optarg;
+ break;
case 'R':
raw_device = true;
break;
@@ -247,6 +269,22 @@ int main(int argc, char *argv[])
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+ if (proto) {
+ unsigned int i;
+
+ for (i = 0; proto_table[i].name; i++) {
+ if (!strcmp(proto_table[i].name, proto)) {
+ proto_id = proto_table[i].id;
+ break;
+ }
+ }
+
+ if (!proto_table[i].name) {
+ fprintf(stderr, "Invalid protocol\n");
+ return EXIT_FAILURE;
+ }
+ }
+
if (bredr_path) {
unsigned long flags;
int fd;
@@ -258,7 +296,7 @@ int main(int argc, char *argv[])
if (raw_device)
flags = (1 << HCI_UART_RAW_DEVICE);
- fd = attach_proto(bredr_path, HCI_UART_H4, flags);
+ fd = attach_proto(bredr_path, proto_id, flags);
if (fd >= 0) {
mainloop_add_fd(fd, 0, uart_callback, NULL, NULL);
count++;
@@ -277,7 +315,7 @@ int main(int argc, char *argv[])
if (raw_device)
flags = (1 << HCI_UART_RAW_DEVICE);
- fd = attach_proto(amp_path, HCI_UART_H4, flags);
+ fd = attach_proto(amp_path, proto_id, flags);
if (fd >= 0) {
mainloop_add_fd(fd, 0, uart_callback, NULL, NULL);
count++;
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index ee5315d4..0f6a1bd5 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -114,6 +114,12 @@ static const char *ecode_to_string(uint8_t ecode)
return "Group type Not Supported";
case BT_ATT_ERROR_INSUFFICIENT_RESOURCES:
return "Insufficient Resources";
+ case BT_ERROR_CCC_IMPROPERLY_CONFIGURED:
+ return "CCC Improperly Configured";
+ case BT_ERROR_ALREADY_IN_PROGRESS:
+ return "Procedure Already in Progress";
+ case BT_ERROR_OUT_OF_RANGE:
+ return "Out of Range";
default:
return "Unknown error type";
}
@@ -179,7 +185,7 @@ static struct client *client_create(int fd, uint16_t mtu)
return NULL;
}
- cli->att = bt_att_new(fd);
+ cli->att = bt_att_new(fd, false);
if (!cli->att) {
fprintf(stderr, "Failed to initialze ATT transport layer\n");
bt_att_unref(cli->att);
@@ -1195,15 +1201,15 @@ static void cmd_unregister_notify(struct client *cli, char *cmd_str)
printf("Unregistered notify handler with id: %u\n", id);
}
-static void set_sec_level_usage(void)
+static void set_security_usage(void)
{
- printf("Usage: set_sec_level <level>\n"
+ printf("Usage: set_security <level>\n"
"level: 1-3\n"
"e.g.:\n"
"\tset-sec-level 2\n");
}
-static void cmd_set_sec_level(struct client *cli, char *cmd_str)
+static void cmd_set_security(struct client *cli, char *cmd_str)
{
char *argvbuf[1];
char **argv = argvbuf;
@@ -1218,12 +1224,12 @@ static void cmd_set_sec_level(struct client *cli, char *cmd_str)
if (!parse_args(cmd_str, 1, argv, &argc)) {
printf("Too many arguments\n");
- set_sec_level_usage();
+ set_security_usage();
return;
}
if (argc < 1) {
- set_sec_level_usage();
+ set_security_usage();
return;
}
@@ -1233,13 +1239,13 @@ static void cmd_set_sec_level(struct client *cli, char *cmd_str)
return;
}
- if (!bt_gatt_client_set_sec_level(cli->gatt, level))
+ if (!bt_gatt_client_set_security(cli->gatt, level))
printf("Could not set sec level\n");
else
printf("Setting security level %d success\n", level);
}
-static void cmd_get_sec_level(struct client *cli, char *cmd_str)
+static void cmd_get_security(struct client *cli, char *cmd_str)
{
int level;
@@ -1248,7 +1254,7 @@ static void cmd_get_sec_level(struct client *cli, char *cmd_str)
return;
}
- level = bt_gatt_client_get_sec_level(cli->gatt);
+ level = bt_gatt_client_get_security(cli->gatt);
if (level < 0)
printf("Could not set sec level\n");
else
@@ -1342,9 +1348,9 @@ static struct {
"\tSubscribe to not/ind from a characteristic" },
{ "unregister-notify", cmd_unregister_notify,
"Unregister a not/ind session"},
- { "set-sec-level", cmd_set_sec_level,
+ { "set-security", cmd_set_security,
"\tSet security level on le connection"},
- { "get-sec-level", cmd_get_sec_level,
+ { "get-security", cmd_get_security,
"\tGet security level on le connection"},
{ "set-sign-key", cmd_set_sign_key,
"\tSet signing key for signed write command"},
diff --git a/tools/btgatt-server.c b/tools/btgatt-server.c
index b30a958f..292b584f 100644
--- a/tools/btgatt-server.c
+++ b/tools/btgatt-server.c
@@ -548,7 +548,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
return NULL;
}
- server->att = bt_att_new(fd);
+ server->att = bt_att_new(fd, false);
if (!server->att) {
fprintf(stderr, "Failed to initialze ATT transport layer\n");
goto fail;
diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index d7af7f08..3d03455f 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -181,6 +181,14 @@ static void print_eir(const uint8_t *eir, uint16_t eir_len)
print("Class of Device: 0x%02x%02x%02x",
eir[4], eir[3], eir[2]);
break;
+ case 0x0e:
+ bin2hex(eir + 2, 16, str, sizeof(str));
+ print("SSP Hash C-192: %s", str);
+ break;
+ case 0x0f:
+ bin2hex(eir + 2, 16, str, sizeof(str));
+ print("SSP Rand R-192: %s", str);
+ break;
case 0x1b:
ba2str((bdaddr_t *) (eir + 2), str);
print("LE Device Address: %s (%s)", str,
@@ -189,6 +197,14 @@ static void print_eir(const uint8_t *eir, uint16_t eir_len)
case 0x1c:
print("LE Role: 0x%02x", eir[2]);
break;
+ case 0x1d:
+ bin2hex(eir + 2, 16, str, sizeof(str));
+ print("SSP Hash C-256: %s", str);
+ break;
+ case 0x1e:
+ bin2hex(eir + 2, 16, str, sizeof(str));
+ print("SSP Rand R-256: %s", str);
+ break;
case 0x22:
bin2hex(eir + 2, 16, str, sizeof(str));
print("LE SC Confirmation Value: %s", str);
@@ -1474,12 +1490,14 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param,
for (i = 0; i < count; i++) {
uint16_t index = le16_to_cpu(rp->entry[i].index);
+ char *busstr = hci_bustostr(rp->entry[i].bus);
if (index_filter != MGMT_INDEX_NONE && index_filter != index)
continue;
switch (rp->entry[i].type) {
case 0x00:
+ print("Primary controller (hci%u,%s)", index, busstr);
if (!mgmt_send(mgmt, MGMT_OP_READ_INFO,
index, 0, NULL, info_rsp,
UINT_TO_PTR(index), NULL)) {
@@ -1489,6 +1507,8 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param,
pending_index++;
break;
case 0x01:
+ print("Unconfigured controller (hci%u,%s)",
+ index, busstr);
if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
index, 0, NULL, config_info_rsp,
UINT_TO_PTR(index), NULL)) {
@@ -1498,16 +1518,17 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param,
pending_index++;
break;
case 0x02:
- print("hci%u:\tAMP controller (%u)", index,
- rp->entry[i].bus);
+ print("AMP controller (hci%u,%s)", index, busstr);
break;
default:
- print("hci%u:\tType %u controller (%u)", index,
- rp->entry[i].type, rp->entry[i].bus);
+ print("Type %u controller (hci%u,%s)",
+ rp->entry[i].type, index, busstr);
break;
}
}
+ print("");
+
if (!count)
noninteractive_quit(EXIT_SUCCESS);
}
@@ -1523,6 +1544,137 @@ static void cmd_extinfo(struct mgmt *mgmt, uint16_t index,
}
}
+static void auto_power_enable_rsp(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ uint16_t index = PTR_TO_UINT(user_data);
+
+ print("Successfully enabled controller with index %u", index);
+
+ noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void auto_power_info_rsp(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_info *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ uint32_t supported_settings, current_settings, missing_settings;
+ uint8_t val = 0x01;
+
+ if (status) {
+ error("Reading info failed with status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ supported_settings = le32_to_cpu(rp->supported_settings);
+ current_settings = le32_to_cpu(rp->current_settings);
+ missing_settings = current_settings ^ supported_settings;
+
+ if (missing_settings & MGMT_SETTING_BREDR)
+ mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, sizeof(val), &val,
+ NULL, NULL, NULL);
+
+ if (missing_settings & MGMT_SETTING_SSP)
+ mgmt_send(mgmt, MGMT_OP_SET_SSP, index, sizeof(val), &val,
+ NULL, NULL, NULL);
+
+ if (missing_settings & MGMT_SETTING_LE)
+ mgmt_send(mgmt, MGMT_OP_SET_LE, index, sizeof(val), &val,
+ NULL, NULL, NULL);
+
+ if (missing_settings & MGMT_SETTING_SECURE_CONN)
+ mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index,
+ sizeof(val), &val,
+ NULL, NULL, NULL);
+
+ if (missing_settings & MGMT_SETTING_BONDABLE)
+ mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, sizeof(val), &val,
+ NULL, NULL, NULL);
+
+ if (current_settings & MGMT_SETTING_POWERED)
+ return noninteractive_quit(EXIT_SUCCESS);
+
+ if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val,
+ auto_power_enable_rsp,
+ UINT_TO_PTR(index), NULL)) {
+ error("Unable to send set powerd cmd");
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
+static void auto_power_index_evt(uint16_t index, uint16_t len,
+ const void *param, void *user_data)
+{
+ uint16_t index_filter = PTR_TO_UINT(user_data);
+
+ if (index != index_filter)
+ return;
+
+ print("New controller with index %u", index);
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+ auto_power_info_rsp,
+ UINT_TO_PTR(index), NULL)) {
+ error("Unable to send read info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
+static void auto_power_index_rsp(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_index_list *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ uint16_t i, count;
+ bool found = false;
+
+ if (status) {
+ error("Reading index list failed with status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ count = le16_to_cpu(rp->num_controllers);
+ for (i = 0; i < count; i++) {
+ if (le16_to_cpu(rp->index[i]) == index)
+ found = true;
+ }
+
+ if (!found) {
+ print("Waiting for index %u to appear", index);
+
+ mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index,
+ auto_power_index_evt,
+ UINT_TO_PTR(index), NULL);
+ return;
+ }
+
+ print("Found controller with index %u", index);
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+ auto_power_info_rsp,
+ UINT_TO_PTR(index), NULL)) {
+ error("Unable to send read info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
+static void cmd_auto_power(struct mgmt *mgmt, uint16_t index,
+ int argc, char **argv)
+{
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+ auto_power_index_rsp,
+ UINT_TO_PTR(index), NULL)) {
+ error("Unable to send read index list cmd");
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
/* Wrapper to get the index and opcode to the response callback */
struct command_data {
uint16_t id;
@@ -2102,19 +2254,21 @@ static struct option find_options[] = {
{ "help", 0, 0, 'h' },
{ "le-only", 1, 0, 'l' },
{ "bredr-only", 1, 0, 'b' },
+ { "limited", 1, 0, 'L' },
{ 0, 0, 0, 0 }
};
static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
{
struct mgmt_cp_start_discovery cp;
+ uint8_t op = MGMT_OP_START_DISCOVERY;
uint8_t type = SCAN_TYPE_DUAL;
int opt;
if (index == MGMT_INDEX_NONE)
index = 0;
- while ((opt = getopt_long(argc, argv, "+lbh", find_options,
+ while ((opt = getopt_long(argc, argv, "+lbLh", find_options,
NULL)) != -1) {
switch (opt) {
case 'l':
@@ -2125,6 +2279,9 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
type |= SCAN_TYPE_BREDR;
type &= ~SCAN_TYPE_LE;
break;
+ case 'L':
+ op = MGMT_OP_START_LIMITED_DISCOVERY;
+ break;
case 'h':
find_usage();
optind = 0;
@@ -2143,8 +2300,8 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
memset(&cp, 0, sizeof(cp));
cp.type = type;
- if (mgmt_send(mgmt, MGMT_OP_START_DISCOVERY, index, sizeof(cp), &cp,
- find_rsp, NULL, NULL) == 0) {
+ if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp,
+ NULL, NULL) == 0) {
error("Unable to send start_discovery cmd");
return noninteractive_quit(EXIT_FAILURE);
}
@@ -2157,8 +2314,7 @@ static void stop_find_rsp(uint8_t status, uint16_t len, const void *param,
fprintf(stderr,
"Stop Discovery failed: status 0x%02x (%s)\n",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_SUCCESS);
}
printf("Discovery stopped\n");
@@ -3715,6 +3871,110 @@ static void cmd_advinfo(struct mgmt *mgmt, uint16_t index,
}
}
+static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_rp_get_adv_size_info *rp = param;
+ uint32_t flags;
+
+ if (status != 0) {
+ error("Reading adv size info failed with status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ if (len < sizeof(*rp)) {
+ error("Too small adv size info reply (%u bytes)", len);
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ flags = le32_to_cpu(rp->flags);
+ print("Instance: %u", rp->instance);
+ print("Flags: %s", adv_flags2str(flags));
+ print("Max advertising data len: %u", rp->max_adv_data_len);
+ print("Max scan response data len: %u", rp->max_scan_rsp_len);
+
+ return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void advsize_usage(void)
+{
+ print("Usage: advsize [options] <instance_id>\nOptions:\n"
+ "\t -c, --connectable \"connectable\" flag\n"
+ "\t -g, --general-discov \"general-discoverable\" flag\n"
+ "\t -l, --limited-discov \"limited-discoverable\" flag\n"
+ "\t -m, --managed-flags \"managed-flags\" flag\n"
+ "\t -p, --tx-power \"tx-power\" flag");
+}
+
+static struct option advsize_options[] = {
+ { "help", 0, 0, 'h' },
+ { "connectable", 0, 0, 'c' },
+ { "general-discov", 0, 0, 'g' },
+ { "limited-discov", 0, 0, 'l' },
+ { "managed-flags", 0, 0, 'm' },
+ { "tx-power", 0, 0, 'p' },
+ { 0, 0, 0, 0}
+};
+
+static void cmd_advsize(struct mgmt *mgmt, uint16_t index,
+ int argc, char **argv)
+{
+ struct mgmt_cp_get_adv_size_info cp;
+ uint8_t instance;
+ uint32_t flags = 0;
+ int opt;
+
+ while ((opt = getopt_long(argc, argv, "+cglmph",
+ advsize_options, NULL)) != -1) {
+ switch (opt) {
+ case 'c':
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ break;
+ case 'g':
+ flags |= MGMT_ADV_FLAG_DISCOV;
+ break;
+ case 'l':
+ flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
+ break;
+ case 'm':
+ flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
+ break;
+ case 'p':
+ flags |= MGMT_ADV_FLAG_TX_POWER;
+ break;
+ default:
+ advsize_usage();
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc != 1) {
+ advsize_usage();
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ instance = strtol(argv[0], NULL, 0);
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+
+ cp.instance = instance;
+ cp.flags = cpu_to_le32(flags);
+
+ if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp,
+ adv_size_info_rsp, NULL, NULL)) {
+ error("Unable to send advertising size info command");
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
@@ -3739,15 +3999,16 @@ static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
static void add_adv_usage(void)
{
print("Usage: add-adv [options] <instance_id>\nOptions:\n"
- "\t -u, --uuid <uuid> Service UUID\n"
- "\t -d, --adv-data <data> Advertising Data bytes\n"
- "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
- "\t -t, --timeout <timeout> Timeout in seconds\n"
- "\t -c, --connectable \"connectable\" flag\n"
- "\t -g, --general-discov \"general-discoverable\" flag\n"
- "\t -l, --limited-discov \"limited-discoverable\" flag\n"
- "\t -m, --managed-flags \"managed-flags\" flag\n"
- "\t -p, --tx-power \"tx-power\" flag\n"
+ "\t -u, --uuid <uuid> Service UUID\n"
+ "\t -d, --adv-data <data> Advertising Data bytes\n"
+ "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
+ "\t -t, --timeout <timeout> Timeout in seconds\n"
+ "\t -D, --duration <duration> Duration in seconds\n"
+ "\t -c, --connectable \"connectable\" flag\n"
+ "\t -g, --general-discov \"general-discoverable\" flag\n"
+ "\t -l, --limited-discov \"limited-discoverable\" flag\n"
+ "\t -m, --managed-flags \"managed-flags\" flag\n"
+ "\t -p, --tx-power \"tx-power\" flag\n"
"e.g.:\n"
"\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
}
@@ -3758,6 +4019,7 @@ static struct option add_adv_options[] = {
{ "adv-data", 1, 0, 'd' },
{ "scan-rsp", 1, 0, 's' },
{ "timeout", 1, 0, 't' },
+ { "duration", 1, 0, 'D' },
{ "connectable", 0, 0, 'c' },
{ "general-discov", 0, 0, 'g' },
{ "limited-discov", 0, 0, 'l' },
@@ -3819,14 +4081,14 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
uint8_t uuids[MAX_AD_UUID_BYTES];
size_t uuid_bytes = 0;
uint8_t uuid_type = 0;
- uint16_t timeout = 0;
+ uint16_t timeout = 0, duration = 0;
uint8_t instance;
uuid_t uuid;
bool success = false;
bool quit = true;
uint32_t flags = 0;
- while ((opt = getopt_long(argc, argv, "+u:d:s:t:cglmph",
+ while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:cglmph",
add_adv_options, NULL)) != -1) {
switch (opt) {
case 'u':
@@ -3887,6 +4149,9 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
case 't':
timeout = strtol(optarg, NULL, 0);
break;
+ case 'D':
+ duration = strtol(optarg, NULL, 0);
+ break;
case 'c':
flags |= MGMT_ADV_FLAG_CONNECTABLE;
break;
@@ -3935,6 +4200,7 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
cp->instance = instance;
put_le32(flags, &cp->flags);
put_le16(timeout, &cp->timeout);
+ put_le16(duration, &cp->duration);
cp->adv_data_len = adv_len + uuid_bytes;
cp->scan_rsp_len = scan_rsp_len;
@@ -4038,6 +4304,7 @@ static struct cmd_info all_cmd[] = {
{ "config", cmd_config, "Show configuration info" },
{ "info", cmd_info, "Show controller info" },
{ "extinfo", cmd_extinfo, "Show extended controller info" },
+ { "auto-power", cmd_auto_power, "Power all available features" },
{ "power", cmd_power, "Toggle powered state" },
{ "discov", cmd_discov, "Toggle discoverable state" },
{ "connectable",cmd_connectable,"Toggle connectable state" },
@@ -4087,6 +4354,7 @@ static struct cmd_info all_cmd[] = {
{ "bredr-oob", cmd_bredr_oob, "Local OOB data (BR/EDR)" },
{ "le-oob", cmd_le_oob, "Local OOB data (LE)" },
{ "advinfo", cmd_advinfo, "Show advertising features" },
+ { "advsize", cmd_advsize, "Show advertising size info" },
{ "add-adv", cmd_add_adv, "Add advertising instance" },
{ "rm-adv", cmd_rm_adv, "Remove advertising instance" },
{ "clr-adv", cmd_clr_adv, "Clear advertising instances" },
@@ -4377,6 +4645,13 @@ static struct io *setup_stdin(void)
return io;
}
+static void mgmt_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ print("%s%s", prefix, str);
+}
+
int main(int argc, char *argv[])
{
struct io *input;
@@ -4412,6 +4687,9 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
+ if (getenv("MGMT_DEBUG"))
+ mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL);
+
if (argc > 0) {
struct cmd_info *c;
diff --git a/tools/btproxy.c b/tools/btproxy.c
index 43ccac17..43de0375 100644
--- a/tools/btproxy.c
+++ b/tools/btproxy.c
@@ -33,6 +33,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <alloca.h>
#include <getopt.h>
#include <stdbool.h>
#include <termios.h>
@@ -45,6 +46,7 @@
#include "src/shared/util.h"
#include "src/shared/mainloop.h"
+#include "src/shared/ecc.h"
#include "monitor/bt.h"
#define HCI_BREDR 0x00
@@ -61,6 +63,7 @@ struct sockaddr_hci {
static uint16_t hci_index = 0;
static bool client_active = false;
static bool debug_enabled = false;
+static bool emulate_ecc = false;
static void hexdump_print(const char *str, void *user_data)
{
@@ -79,6 +82,10 @@ struct proxy {
uint8_t dev_buf[4096];
uint16_t dev_len;
bool dev_shutdown;
+
+ /* ECC emulation */
+ uint8_t event_mask[8];
+ uint8_t local_sk256[32];
};
static bool write_packet(int fd, const void *data, size_t size,
@@ -105,6 +112,162 @@ static bool write_packet(int fd, const void *data, size_t size,
return true;
}
+static void host_write_packet(struct proxy *proxy, void *buf, uint16_t len)
+{
+ if (!write_packet(proxy->dev_fd, buf, len, "D: ")) {
+ fprintf(stderr, "Write to device descriptor failed\n");
+ mainloop_remove_fd(proxy->dev_fd);
+ }
+}
+
+static void dev_write_packet(struct proxy *proxy, void *buf, uint16_t len)
+{
+ if (!write_packet(proxy->host_fd, buf, len, "H: ")) {
+ fprintf(stderr, "Write to host descriptor failed\n");
+ mainloop_remove_fd(proxy->host_fd);
+ }
+}
+
+static void cmd_status(struct proxy *proxy, uint8_t status, uint16_t opcode)
+{
+ size_t buf_size = 1 + sizeof(struct bt_hci_evt_hdr) +
+ sizeof(struct bt_hci_evt_cmd_status);
+ void *buf = alloca(buf_size);
+ struct bt_hci_evt_hdr *hdr = buf + 1;
+ struct bt_hci_evt_cmd_status *cs = buf + 1 + sizeof(*hdr);
+
+ *((uint8_t *) buf) = BT_H4_EVT_PKT;
+
+ hdr->evt = BT_HCI_EVT_CMD_STATUS;
+ hdr->plen = sizeof(*cs);
+
+ cs->status = status;
+ cs->ncmd = 0x01;
+ cs->opcode = cpu_to_le16(opcode);
+
+ dev_write_packet(proxy, buf, buf_size);
+}
+
+static void le_meta_event(struct proxy *proxy, uint8_t event,
+ void *data, uint8_t len)
+{
+ size_t buf_size = 1 + sizeof(struct bt_hci_evt_hdr) + 1 + len;
+ void *buf = alloca(buf_size);
+ struct bt_hci_evt_hdr *hdr = buf + 1;
+
+ *((uint8_t *) buf) = BT_H4_EVT_PKT;
+
+ hdr->evt = BT_HCI_EVT_LE_META_EVENT;
+ hdr->plen = 1 + len;
+
+ *((uint8_t *) (buf + 1 + sizeof(*hdr))) = event;
+
+ if (len > 0)
+ memcpy(buf + 1 + sizeof(*hdr) + 1, data, len);
+
+ dev_write_packet(proxy, buf, buf_size);
+}
+
+static void host_emulate_ecc(struct proxy *proxy, void *buf, uint16_t len)
+{
+ uint8_t pkt_type = *((uint8_t *) buf);
+ struct bt_hci_cmd_hdr *hdr = buf + 1;
+ struct bt_hci_cmd_le_set_event_mask *lsem;
+ struct bt_hci_cmd_le_generate_dhkey *lgd;
+ struct bt_hci_evt_le_read_local_pk256_complete lrlpkc;
+ struct bt_hci_evt_le_generate_dhkey_complete lgdc;
+
+ if (pkt_type != BT_H4_CMD_PKT) {
+ host_write_packet(proxy, buf, len);
+ return;
+ }
+
+ switch (le16_to_cpu(hdr->opcode)) {
+ case BT_HCI_CMD_LE_SET_EVENT_MASK:
+ lsem = buf + 1 + sizeof(*hdr);
+ memcpy(proxy->event_mask, lsem->mask, 8);
+
+ lsem->mask[0] &= ~0x80; /* P-256 Public Key Complete */
+ lsem->mask[1] &= ~0x01; /* Generate DHKey Complete */
+
+ host_write_packet(proxy, buf, len);
+ break;
+
+ case BT_HCI_CMD_LE_READ_LOCAL_PK256:
+ if (!ecc_make_key(lrlpkc.local_pk256, proxy->local_sk256)) {
+ cmd_status(proxy, BT_HCI_ERR_COMMAND_DISALLOWED,
+ BT_HCI_CMD_LE_READ_LOCAL_PK256);
+ break;
+ }
+ cmd_status(proxy, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_READ_LOCAL_PK256);
+
+ if (!(proxy->event_mask[0] & 0x80))
+ break;
+
+ lrlpkc.status = BT_HCI_ERR_SUCCESS;
+ le_meta_event(proxy, BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE,
+ &lrlpkc, sizeof(lrlpkc));
+ break;
+
+ case BT_HCI_CMD_LE_GENERATE_DHKEY:
+ lgd = buf + 1 + sizeof(*hdr);
+ if (!ecdh_shared_secret(lgd->remote_pk256, proxy->local_sk256,
+ lgdc.dhkey)) {
+ cmd_status(proxy, BT_HCI_ERR_COMMAND_DISALLOWED,
+ BT_HCI_CMD_LE_GENERATE_DHKEY);
+ break;
+ }
+ cmd_status(proxy, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_GENERATE_DHKEY);
+
+ if (!(proxy->event_mask[1] & 0x01))
+ break;
+
+ lgdc.status = BT_HCI_ERR_SUCCESS;
+ le_meta_event(proxy, BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE,
+ &lgdc, sizeof(lgdc));
+ break;
+
+ default:
+ host_write_packet(proxy, buf, len);
+ break;
+ }
+}
+
+static void dev_emulate_ecc(struct proxy *proxy, void *buf, uint16_t len)
+{
+ uint8_t pkt_type = *((uint8_t *) buf);
+ struct bt_hci_evt_hdr *hdr = buf + 1;
+ struct bt_hci_evt_cmd_complete *cc;
+ struct bt_hci_rsp_read_local_commands *rlc;
+
+ if (pkt_type != BT_H4_EVT_PKT) {
+ dev_write_packet(proxy, buf, len);
+ return;
+ }
+
+ switch (hdr->evt) {
+ case BT_HCI_EVT_CMD_COMPLETE:
+ cc = buf + 1 + sizeof(*hdr);
+
+ switch (le16_to_cpu(cc->opcode)) {
+ case BT_HCI_CMD_READ_LOCAL_COMMANDS:
+ rlc = buf + 1 + sizeof(*hdr) + sizeof(*cc);
+ rlc->commands[34] |= 0x02; /* P-256 Public Key */
+ rlc->commands[34] |= 0x04; /* Generate DHKey */
+ break;
+ }
+
+ dev_write_packet(proxy, buf, len);
+ break;
+
+ default:
+ dev_write_packet(proxy, buf, len);
+ break;
+ }
+}
+
static void host_read_destroy(void *user_data)
{
struct proxy *proxy = user_data;
@@ -202,11 +365,10 @@ process_packet:
if (proxy->host_len < pktlen)
return;
- if (!write_packet(proxy->dev_fd, proxy->host_buf, pktlen, "D: ")) {
- fprintf(stderr, "Write to device descriptor failed\n");
- mainloop_remove_fd(proxy->dev_fd);
- return;
- }
+ if (emulate_ecc)
+ host_emulate_ecc(proxy, proxy->host_buf, pktlen);
+ else
+ host_write_packet(proxy, proxy->host_buf, pktlen);
if (proxy->host_len > pktlen) {
memmove(proxy->host_buf, proxy->host_buf + pktlen,
@@ -311,11 +473,10 @@ process_packet:
if (proxy->dev_len < pktlen)
return;
- if (!write_packet(proxy->host_fd, proxy->dev_buf, pktlen, "H: ")) {
- fprintf(stderr, "Write to host descriptor failed\n");
- mainloop_remove_fd(proxy->host_fd);
- return;
- }
+ if (emulate_ecc)
+ dev_emulate_ecc(proxy, proxy->dev_buf, pktlen);
+ else
+ dev_write_packet(proxy, proxy->dev_buf, pktlen);
if (proxy->dev_len > pktlen) {
memmove(proxy->dev_buf, proxy->dev_buf + pktlen,
@@ -334,7 +495,10 @@ static bool setup_proxy(int host_fd, bool host_shutdown,
proxy = new0(struct proxy, 1);
if (!proxy)
- return NULL;
+ return false;
+
+ if (emulate_ecc)
+ printf("Enabling ECC emulation\n");
proxy->host_fd = host_fd;
proxy->host_shutdown = host_shutdown;
@@ -567,20 +731,23 @@ static void usage(void)
"\t-p, --port <port> Use specified TCP port\n"
"\t-i, --index <num> Use specified controller\n"
"\t-a, --amp Create AMP controller\n"
+ "\t-e, --ecc Emulate ECC support\n"
"\t-d, --debug Enable debugging output\n"
"\t-h, --help Show help options\n");
}
static const struct option main_options[] = {
- { "connect", required_argument, NULL, 'c' },
- { "listen", optional_argument, NULL, 'l' },
- { "unix", optional_argument, NULL, 'u' },
- { "port", required_argument, NULL, 'p' },
- { "index", required_argument, NULL, 'i' },
- { "amp", no_argument, NULL, 'a' },
- { "debug", no_argument, NULL, 'd' },
- { "version", no_argument, NULL, 'v' },
- { "help", no_argument, NULL, 'h' },
+ { "redirect", no_argument, NULL, 'r' },
+ { "connect", required_argument, NULL, 'c' },
+ { "listen", optional_argument, NULL, 'l' },
+ { "unix", optional_argument, NULL, 'u' },
+ { "port", required_argument, NULL, 'p' },
+ { "index", required_argument, NULL, 'i' },
+ { "amp", no_argument, NULL, 'a' },
+ { "ecc", no_argument, NULL, 'e' },
+ { "debug", no_argument, NULL, 'd' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
{ }
};
@@ -590,6 +757,7 @@ int main(int argc, char *argv[])
const char *server_address = NULL;
const char *unix_path = NULL;
unsigned short tcp_port = 0xb1ee; /* 45550 */
+ bool use_redirect = false;
uint8_t type = HCI_BREDR;
const char *str;
sigset_t mask;
@@ -597,14 +765,14 @@ int main(int argc, char *argv[])
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "ac:l::u::p:i:dvh",
+ opt = getopt_long(argc, argv, "rc:l::u::p:i:aedvh",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
- case 'a':
- type = HCI_AMP;
+ case 'r':
+ use_redirect = true;
break;
case 'c':
connect_address = optarg;
@@ -635,6 +803,12 @@ int main(int argc, char *argv[])
}
hci_index = atoi(str);
break;
+ case 'a':
+ type = HCI_AMP;
+ break;
+ case 'e':
+ emulate_ecc = true;
+ break;
case 'd':
debug_enabled = true;
break;
@@ -654,12 +828,12 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- if (unix_path && server_address) {
+ if (unix_path && (server_address || use_redirect)) {
fprintf(stderr, "Invalid to specify TCP and Unix servers\n");
return EXIT_FAILURE;
}
- if (connect_address && (unix_path || server_address)) {
+ if (connect_address && (unix_path || server_address || use_redirect)) {
fprintf(stderr, "Invalid to specify client and server mode\n");
return EXIT_FAILURE;
}
@@ -672,12 +846,20 @@ int main(int argc, char *argv[])
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
- if (connect_address) {
+ if (connect_address || use_redirect) {
int host_fd, dev_fd;
- printf("Connecting to %s:%u\n", connect_address, tcp_port);
+ if (use_redirect) {
+ printf("Creating local redirect\n");
+
+ dev_fd = open_channel(hci_index);
+ } else {
+ printf("Connecting to %s:%u\n", connect_address,
+ tcp_port);
+
+ dev_fd = connect_tcp(connect_address, tcp_port);
+ }
- dev_fd = connect_tcp(connect_address, tcp_port);
if (dev_fd < 0)
return EXIT_FAILURE;
diff --git a/tools/btsnoop.c b/tools/btsnoop.c
index 278e18ce..814e5e15 100644
--- a/tools/btsnoop.c
+++ b/tools/btsnoop.c
@@ -34,8 +34,10 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
+#ifdef __TIZEN_PATCH__
#include <time.h>
#include <sys/time.h>
+#endif
#include <getopt.h>
#include <endian.h>
#include <arpa/inet.h>
@@ -273,7 +275,7 @@ close_input:
for (i = 0; i < num_input; i++)
close(input_fd[i]);
}
-
+#ifdef __TIZEN_PATCH__
#define BT_SNOOP_TYPE_HCI_PREFIX "btsnoop_type_hci"
static void command_split(const char *input)
@@ -294,8 +296,8 @@ static void command_split(const char *input)
if (!btsnoop_read_file)
return;
- type = btsnoop_get_type(btsnoop_read_file);
- if (type != BTSNOOP_TYPE_MONITOR) {
+ type = btsnoop_get_format(btsnoop_read_file);
+ if (type != BTSNOOP_FORMAT_MONITOR) {
fprintf(stderr, "unsupported link data type %u\n", type);
btsnoop_unref(btsnoop_read_file);
return;
@@ -325,7 +327,7 @@ next_packet:
write_file_name);
btsnoop_write_file[index] = btsnoop_create(write_file_name,
- BTSNOOP_TYPE_HCI, -1, -1);
+ BTSNOOP_FORMAT_HCI, -1, -1);
if (!btsnoop_write_file[index])
goto close_files;
@@ -337,8 +339,30 @@ next_packet:
btsnoop_write_file[index] = NULL;
break;
default:
+ if (!btsnoop_write_file[index]) {
+ t = tv.tv_sec;
+ localtime_r(&t, &tm);
+
+ if (max_index < index)
+ max_index = index;
+
+ sprintf(write_file_name, "%s%d_%02d:%02d:%02d.%06lu.log",
+ BT_SNOOP_TYPE_HCI_PREFIX, index,
+ tm.tm_hour, tm.tm_min,
+ tm.tm_sec, tv.tv_usec);
+
+ printf("New Index %d would be saved in %s\n", index,
+ write_file_name);
+
+ btsnoop_write_file[index] = btsnoop_create(write_file_name,
+ BTSNOOP_FORMAT_HCI, -1, -1);
+ }
+
+ if (!btsnoop_write_file[index])
+ goto close_files;
btsnoop_write_hci(btsnoop_write_file[index], &tv, index,
opcode, buf, pktlen);
+ break;
}
num_packets++;
@@ -353,6 +377,7 @@ close_files:
printf("BT Snoop data link transfer is completed for %lu packets\n",
num_packets);
}
+#endif
static void command_extract_eir(const char *input)
{
@@ -600,7 +625,9 @@ static void usage(void)
printf("commands:\n"
"\t-m, --merge <output> Merge multiple btsnoop files\n"
"\t-e, --extract <input> Extract data from btsnoop file\n"
+#ifdef __TIZEN_PATCH__
"\t-s, --split <input> Split btmon file into legacy btsnoop file(s)\n"
+#endif
"\t-h, --help Show help options\n");
}
@@ -608,13 +635,19 @@ static const struct option main_options[] = {
{ "merge", required_argument, NULL, 'm' },
{ "extract", required_argument, NULL, 'e' },
{ "type", required_argument, NULL, 't' },
+#ifdef __TIZEN_PATCH__
{ "split", required_argument, NULL, 's' },
+#endif
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
};
+#ifdef __TIZEN_PATCH__
enum { INVALID, MERGE, EXTRACT, SPLIT };
+#else
+enum { INVALID, MERGE, EXTRACT };
+#endif
int main(int argc, char *argv[])
{
@@ -625,8 +658,11 @@ int main(int argc, char *argv[])
for (;;) {
int opt;
-
+#ifdef __TIZEN_PATCH__
opt = getopt_long(argc, argv, "m:e:s:t:vh", main_options, NULL);
+#else
+ opt = getopt_long(argc, argv, "m:e:t:vh", main_options, NULL);
+#endif
if (opt < 0)
break;
@@ -639,9 +675,11 @@ int main(int argc, char *argv[])
command = EXTRACT;
input_path = optarg;
break;
+#ifdef __TIZEN_PATCH__
case 's':
command = SPLIT;
input_path = optarg;
+#endif
case 't':
type = optarg;
break;
@@ -687,6 +725,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "extract type not supported\n");
break;
+#ifdef __TIZEN_PATCH__
case SPLIT:
if (argc - optind > 0) {
fprintf(stderr, "extra arguments not allowed\n");
@@ -695,7 +734,7 @@ int main(int argc, char *argv[])
command_split(input_path);
break;
-
+#endif
default:
usage();
return EXIT_FAILURE;
diff --git a/tools/check-selftest.c b/tools/check-selftest.c
new file mode 100644
index 00000000..6006b80a
--- /dev/null
+++ b/tools/check-selftest.c
@@ -0,0 +1,71 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+static void check_result(const char *name, const char *pathname)
+{
+ FILE *fp;
+ int i;
+
+ for (i = 0; i < 50; i++) {
+ struct stat st;
+
+ if (!stat(pathname, &st)) {
+ printf("Found %s selftest result\n", name);
+ break;
+ }
+
+ usleep(25 * 1000);
+ }
+
+ fp = fopen(pathname, "re");
+ if (fp) {
+ char result[32], *ptr;
+
+ ptr = fgets(result, sizeof(result), fp);
+ fclose(fp);
+
+ ptr = strpbrk(result, "\r\n");
+ if (ptr)
+ *ptr = '\0';
+
+ printf("%s: %s\n", name, result);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ check_result("ECDH", "/sys/kernel/debug/bluetooth/selftest_ecdh");
+ check_result("SMP", "/sys/kernel/debug/bluetooth/selftest_smp");
+
+ return 0;
+}
diff --git a/tools/create-image.c b/tools/create-image.c
new file mode 100644
index 00000000..d94f99d9
--- /dev/null
+++ b/tools/create-image.c
@@ -0,0 +1,205 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <inttypes.h>
+
+/*
+ * The "new" ASCII format uses 8-byte hexadecimal fields for all numbers and
+ * separates device numbers into separate fields for major and minor numbers.
+ *
+ * struct cpio_newc_header {
+ * char c_magic[6];
+ * char c_ino[8];
+ * char c_mode[8];
+ * char c_uid[8];
+ * char c_gid[8];
+ * char c_nlink[8];
+ * char c_mtime[8];
+ * char c_filesize[8];
+ * char c_devmajor[8];
+ * char c_devminor[8];
+ * char c_rdevmajor[8];
+ * char c_rdevminor[8];
+ * char c_namesize[8];
+ * char c_check[8];
+ * };
+ *
+ */
+
+#define HDR_FMT "%s%08X%08X%08X%08X%08X%08X%08jX%08X%08X%08X%08X%08X%08X%s"
+
+#define HDR_MAGIC "070701"
+
+static unsigned int ino_cnt = 721;
+
+#define REG_EXE S_IFREG | \
+ S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
+
+static const struct {
+ const char *source;
+ const char *target;
+ mode_t mode;
+} file_list[] = {
+ { "tools/test-runner", "init", REG_EXE },
+ { }
+};
+
+static void write_block(FILE *fp, const char *pathname, unsigned int ino,
+ mode_t mode, const char *name)
+{
+ int i, pad, namelen = strlen(name);
+ struct stat st;
+ void *map;
+ int fd;
+
+ if (!pathname) {
+ fd = -1;
+ map = NULL;
+ st.st_size = 0;
+ goto done;
+ }
+
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ fd = -1;
+ map = NULL;
+ st.st_size = 0;
+ goto done;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ close(fd);
+ fd = -1;
+ map = NULL;
+ st.st_size = 0;
+ goto done;
+ }
+
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ close(fd);
+ fd = -1;
+ map = NULL;
+ st.st_size = 0;
+ }
+
+done:
+ fprintf(fp, HDR_FMT, HDR_MAGIC, ino, mode, 0, 0, 1, 0,
+ (uintmax_t) st.st_size, 0, 0, 0, 0, namelen + 1, 0, name);
+
+ pad = 4 - ((110 + namelen) % 4);
+ for (i = 0; i < pad; i++)
+ fputc(0, fp);
+
+ if (st.st_size > 0) {
+ fwrite(map, st.st_size, 1, fp);
+
+ pad = 3 - ((st.st_size + 3) % 4);
+ for (i = 0; i < pad; i++)
+ fputc(0, fp);
+
+ munmap(map, st.st_size);
+ close(fd);
+ }
+}
+
+static void usage(void)
+{
+ printf("create-image - CPIO image creation utility\n"
+ "Usage:\n");
+ printf("\tcreate-image [options]\n");
+ printf("Options:\n"
+ "\t-o, --output <image> Output CPIO image\n"
+ "\t-h, --help Show help options\n");
+}
+
+static const struct option main_options[] = {
+ { "output", required_argument, NULL, 'o' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
+int main(int argc, char *argv[])
+{
+ const char *output_pathname = NULL;
+ FILE *fp;
+ int i;
+
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "o:vh", main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'o':
+ output_pathname = optarg;
+ break;
+ case 'v':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (argc - optind > 0) {
+ fprintf(stderr, "Invalid command line parameters\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!output_pathname) {
+ fprintf(stderr, "Failed to specify output file\n");
+ return EXIT_FAILURE;
+ }
+
+ fp = fopen(output_pathname, "we");
+
+ for (i = 0; file_list[i].source; i++)
+ write_block(fp, file_list[i].source, ino_cnt++,
+ file_list[i].mode, file_list[i].target);
+
+ write_block(fp, NULL, ino_cnt++, 0, "TRAILER!!!");
+
+ fclose(fp);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/csr.h b/tools/csr.h
index 8b94d7b8..cc245a55 100644
--- a/tools/csr.h
+++ b/tools/csr.h
@@ -39,6 +39,7 @@
#define CSR_VARID_BT_CLOCK 0x2c00 /* uint32 */
#define CSR_VARID_PS_NEXT 0x3005 /* complex */
#define CSR_VARID_PS_SIZE 0x3006 /* complex */
+#define CSR_VARID_ADC_RES 0x3007 /* complex */
#define CSR_VARID_CRYPT_KEY_LENGTH 0x3008 /* complex */
#define CSR_VARID_PICONET_INSTANCE 0x3009 /* complex */
#define CSR_VARID_GET_CLR_EVT 0x300a /* complex */
@@ -62,6 +63,7 @@
#define CSR_VARID_CANCEL_PAGE 0x4012 /* valueless */
#define CSR_VARID_PS_CLR 0x4818 /* uint16 */
#define CSR_VARID_MAP_SCO_PCM 0x481c /* uint16 */
+#define CSR_VARID_ADC 0x4829 /* uint16 */
#define CSR_VARID_SINGLE_CHAN 0x482e /* uint16 */
#define CSR_VARID_RADIOTEST 0x5004 /* complex */
#define CSR_VARID_PS_CLR_STORES 0x500c /* complex */
diff --git a/tools/eddystone.c b/tools/eddystone.c
new file mode 100644
index 00000000..23a34f9d
--- /dev/null
+++ b/tools/eddystone.c
@@ -0,0 +1,319 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "monitor/bt.h"
+#include "src/shared/mainloop.h"
+#include "src/shared/timeout.h"
+#include "src/shared/util.h"
+#include "src/shared/hci.h"
+
+static int urandom_fd;
+static struct bt_hci *hci_dev;
+
+static bool shutdown_timeout(void *user_data)
+{
+ mainloop_quit();
+
+ return false;
+}
+
+static void shutdown_complete(const void *data, uint8_t size, void *user_data)
+{
+ unsigned int id = PTR_TO_UINT(user_data);
+
+ timeout_remove(id);
+ mainloop_quit();
+}
+
+static void shutdown_device(void)
+{
+ uint8_t enable = 0x00;
+ unsigned int id;
+
+ bt_hci_flush(hci_dev);
+
+ id = timeout_add(5000, shutdown_timeout, NULL, NULL);
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_ENABLE,
+ &enable, 1, NULL, NULL, NULL);
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
+ shutdown_complete, UINT_TO_PTR(id), NULL);
+}
+
+static void set_random_address(void)
+{
+ struct bt_hci_cmd_le_set_random_address cmd;
+ ssize_t len;
+
+ len = read(urandom_fd, cmd.addr, sizeof(cmd.addr));
+ if (len < 0 || len != sizeof(cmd.addr)) {
+ fprintf(stderr, "Failed to read random data\n");
+ return;
+ }
+
+ /* Clear top most significant bits */
+ cmd.addr[5] &= 0x3f;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_RANDOM_ADDRESS,
+ &cmd, sizeof(cmd), NULL, NULL, NULL);
+}
+
+static void set_adv_parameters(void)
+{
+ struct bt_hci_cmd_le_set_adv_parameters cmd;
+
+ cmd.min_interval = cpu_to_le16(0x0800);
+ cmd.max_interval = cpu_to_le16(0x0800);
+ cmd.type = 0x03; /* Non-connectable advertising */
+ cmd.own_addr_type = 0x01; /* Use random address */
+ cmd.direct_addr_type = 0x00;
+ memset(cmd.direct_addr, 0, 6);
+ cmd.channel_map = 0x07;
+ cmd.filter_policy = 0x00;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+ &cmd, sizeof(cmd), NULL, NULL, NULL);
+}
+
+static void set_adv_enable(void)
+{
+ uint8_t enable = 0x01;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_ENABLE,
+ &enable, 1, NULL, NULL, NULL);
+}
+
+static void adv_data_callback(const void *data, uint8_t size,
+ void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ fprintf(stderr, "Failed to set advertising data\n");
+ shutdown_device();
+ return;
+ }
+
+ set_random_address();
+ set_adv_parameters();
+ set_adv_enable();
+}
+
+static void adv_tx_power_callback(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_le_read_adv_tx_power *rsp = data;
+ struct bt_hci_cmd_le_set_adv_data cmd;
+
+ if (rsp->status) {
+ fprintf(stderr, "Failed to read advertising TX power\n");
+ shutdown_device();
+ return;
+ }
+
+ cmd.data[0] = 0x02; /* Field length */
+ cmd.data[1] = 0x01; /* Flags */
+ cmd.data[2] = 0x02; /* LE General Discoverable Mode */
+ cmd.data[2] |= 0x04; /* BR/EDR Not Supported */
+
+ cmd.data[3] = 0x03; /* Field length */
+ cmd.data[4] = 0x03; /* 16-bit Service UUID list */
+ cmd.data[5] = 0xaa; /* Eddystone UUID */
+ cmd.data[6] = 0xfe;
+
+ cmd.data[7] = 0x0c; /* Field length */
+ cmd.data[8] = 0x16; /* 16-bit Service UUID data */
+ cmd.data[9] = 0xaa; /* Eddystone UUID */
+ cmd.data[10] = 0xfe;
+ cmd.data[11] = 0x10; /* Eddystone-URL frame type */
+ cmd.data[12] = 0x00; /* Calibrated Tx power at 0m */
+ cmd.data[13] = 0x00; /* URL Scheme Prefix http://www. */
+ cmd.data[14] = 'b';
+ cmd.data[15] = 'l';
+ cmd.data[16] = 'u';
+ cmd.data[17] = 'e';
+ cmd.data[18] = 'z';
+ cmd.data[19] = 0x01; /* .org/ */
+
+ cmd.data[20] = 0x00; /* Field terminator */
+ memset(cmd.data + 21, 0, 9);
+
+ cmd.len = 1 + cmd.data[0] + 1 + cmd.data[3] + 1 + cmd.data[7];
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_DATA, &cmd, sizeof(cmd),
+ adv_data_callback, NULL, NULL);
+}
+
+static void local_features_callback(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_read_local_features *rsp = data;
+
+ if (rsp->status) {
+ fprintf(stderr, "Failed to read local features\n");
+ shutdown_device();
+ return;
+ }
+
+ if (!(rsp->features[4] & 0x40)) {
+ fprintf(stderr, "Controller without Low Energy support\n");
+ shutdown_device();
+ return;
+ }
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_LE_READ_ADV_TX_POWER, NULL, 0,
+ adv_tx_power_callback, NULL, NULL);
+}
+
+static void start_eddystone(void)
+{
+ bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0, NULL, NULL, NULL);
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
+ local_features_callback, NULL, NULL);
+}
+
+static void signal_callback(int signum, void *user_data)
+{
+ static bool terminated = false;
+
+ switch (signum) {
+ case SIGINT:
+ case SIGTERM:
+ if (!terminated) {
+ shutdown_device();
+ terminated = true;
+ }
+ break;
+ }
+}
+
+static void usage(void)
+{
+ printf("eddystone - Low Energy Eddystone testing tool\n"
+ "Usage:\n");
+ printf("\teddystone [options]\n");
+ printf("Options:\n"
+ "\t-i, --index <num> Use specified controller\n"
+ "\t-h, --help Show help options\n");
+}
+
+static const struct option main_options[] = {
+ { "index", required_argument, NULL, 'i' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
+int main(int argc, char *argv[])
+{
+ uint16_t index = 0;
+ const char *str;
+ sigset_t mask;
+ int exit_status;
+
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "i:vh", main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'i':
+ if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
+ str = optarg + 3;
+ else
+ str = optarg;
+ if (!isdigit(*str)) {
+ usage();
+ return EXIT_FAILURE;
+ }
+ index = atoi(str);
+ break;
+ case 'v':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (argc - optind > 0) {
+ fprintf(stderr, "Invalid command line parameters\n");
+ return EXIT_FAILURE;
+ }
+
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (urandom_fd < 0) {
+ fprintf(stderr, "Failed to open /dev/urandom device\n");
+ return EXIT_FAILURE;
+ }
+
+ mainloop_init();
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+ printf("Low Energy Eddystone utility ver %s\n", VERSION);
+
+ hci_dev = bt_hci_new_user_channel(index);
+ if (!hci_dev) {
+ fprintf(stderr, "Failed to open HCI user channel\n");
+ exit_status = EXIT_FAILURE;
+ goto done;
+ }
+
+ start_eddystone();
+
+ exit_status = mainloop_run();
+
+ bt_hci_unref(hci_dev);
+
+done:
+ close(urandom_fd);
+
+ return exit_status;
+}
diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index 33e0d6a0..9baa9e14 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -74,9 +74,7 @@ struct descriptor {
* properties are defined at doc/gatt-api.txt. See "Flags"
* property of the GattCharacteristic1.
*/
-static const char const *ias_alert_level_props[] = {
- "write-without-response",
- NULL };
+static const char *ias_alert_level_props[] = { "write-without-response", NULL };
static gboolean desc_get_uuid(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
diff --git a/tools/hci-tester.c b/tools/hci-tester.c
index a5dbde2c..75d09f07 100644
--- a/tools/hci-tester.c
+++ b/tools/hci-tester.c
@@ -31,6 +31,7 @@
#include "monitor/bt.h"
#include "src/shared/hci.h"
#include "src/shared/util.h"
+#include "src/shared/ecc.h"
#include "src/shared/tester.h"
struct user_data {
@@ -45,6 +46,24 @@ struct user_data {
uint16_t handle_ut;
};
+struct le_keys {
+ uint8_t remote_sk[32];
+ uint8_t local_pk[64];
+} key_test_data;
+
+static void swap_buf(const uint8_t *src, uint8_t *dst, uint16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ dst[len - 1 - i] = src[i];
+}
+
+static void test_debug(const char *str, void *user_data)
+{
+ tester_debug("%s", str);
+}
+
static void test_pre_setup_lt_address(const void *data, uint8_t size,
void *user_data)
{
@@ -339,6 +358,258 @@ static void test_le_clear_white_list(const void *test_data)
test_command(BT_HCI_CMD_LE_CLEAR_WHITE_LIST);
}
+static void test_le_encrypt_complete(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_le_encrypt *rsp = data;
+ uint8_t sample[16] = {
+ 0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
+ 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f
+ };
+ uint8_t enc_data[16];
+
+ if (rsp->status) {
+ tester_warn("Failed HCI LE Encrypt (0x%02x)", rsp->status);
+ tester_test_failed();
+ return;
+ }
+
+ swap_buf(rsp->data, enc_data, 16);
+ util_hexdump('>', enc_data, 16, test_debug, NULL);
+
+ if (!memcmp(sample, enc_data, 16))
+ tester_test_passed();
+ else
+ tester_test_failed();
+}
+
+/* Data are taken from RFC 4493 Test Vectors */
+static void test_le_encrypt(const void *test_data)
+{
+ struct user_data *user = tester_get_data();
+ struct bt_hci_cmd_le_encrypt cmd;
+ uint8_t key[16] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ uint8_t plaintext[16] = { 0 };
+
+ /* Swap bytes since our interface has LE interface, opposed to
+ * common crypto interface
+ */
+ swap_buf(key, cmd.key, 16);
+ swap_buf(plaintext, cmd.plaintext, 16);
+
+ util_hexdump('<', cmd.key, 16, test_debug, NULL);
+ util_hexdump('<', cmd.plaintext, 16, test_debug, NULL);
+
+ if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_ENCRYPT, &cmd, sizeof(cmd),
+ test_le_encrypt_complete, NULL, NULL)) {
+ tester_warn("Failed to send HCI LE Encrypt command");
+ tester_test_failed();
+ return;
+ }
+
+}
+
+static void test_le_rand(const void *test_data)
+{
+ test_command(BT_HCI_CMD_LE_RAND);
+}
+
+static void test_le_read_local_pk_complete(const void *data, uint8_t size,
+ void *user_data)
+{
+ const uint8_t *event = data;
+ const struct bt_hci_evt_le_read_local_pk256_complete *evt;
+ struct le_keys *keys = user_data;
+
+ if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) {
+ tester_warn("Failed Read Local PK256 command");
+ tester_test_failed();
+ return;
+ }
+
+ evt = (void *)(event + 1);
+ if (evt->status) {
+ tester_warn("HCI Read Local PK complete failed (0x%02x)",
+ evt->status);
+ tester_test_failed();
+ return;
+ }
+
+ memcpy(keys->local_pk, evt->local_pk256, 64);
+
+ util_hexdump('>', evt->local_pk256, 64, test_debug, NULL);
+
+ tester_test_passed();
+}
+
+static void test_le_read_local_pk_status(const void *data, uint8_t size,
+ void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ tester_warn("Failed to send DHKey gen cmd (0x%02x)", status);
+ tester_test_failed();
+ return;
+ }
+}
+
+static void test_le_read_local_pk(const void *test_data)
+{
+ struct user_data *user = tester_get_data();
+
+ bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+ test_le_read_local_pk_complete,
+ (void *)test_data, NULL);
+
+ if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_READ_LOCAL_PK256, NULL,
+ 0, test_le_read_local_pk_status,
+ NULL, NULL)) {
+ tester_warn("Failed to send HCI LE Read Local PK256 command");
+ tester_test_failed();
+ return;
+ }
+}
+
+static void setup_le_read_local_pk_complete(const void *data, uint8_t size,
+ void *user_data)
+{
+ const uint8_t *event = data;
+ const struct bt_hci_evt_le_read_local_pk256_complete *evt;
+ struct le_keys *keys = user_data;
+
+ if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) {
+ tester_warn("Failed Read Local PK256 command");
+ tester_setup_failed();
+ return;
+ }
+
+ evt = (void *)(event + 1);
+ if (evt->status) {
+ tester_warn("HCI Read Local PK complete failed (0x%02x)",
+ evt->status);
+ tester_setup_failed();
+ return;
+ }
+
+ memcpy(keys->local_pk, evt->local_pk256, 64);
+
+ util_hexdump('>', evt->local_pk256, 64, test_debug, NULL);
+
+ tester_setup_complete();
+}
+
+static void setup_le_read_local_pk_status(const void *data, uint8_t size,
+ void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ tester_warn("Failed to send DHKey gen cmd (0x%02x)", status);
+ tester_setup_failed();
+ return;
+ }
+}
+
+static void setup_le_generate_dhkey(const void *test_data)
+{
+ struct user_data *user = tester_get_data();
+
+ bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+ setup_le_read_local_pk_complete,
+ (void *)test_data, NULL);
+
+ if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_READ_LOCAL_PK256, NULL,
+ 0, setup_le_read_local_pk_status,
+ NULL, NULL)) {
+ tester_warn("Failed to send HCI LE Read Local PK256 command");
+ tester_setup_failed();
+ return;
+ }
+}
+
+static void test_le_generate_dhkey_complete(const void *data, uint8_t size,
+ void *user_data)
+{
+ const uint8_t *event = data;
+ const struct bt_hci_evt_le_generate_dhkey_complete *evt;
+ struct le_keys *keys = user_data;
+ uint8_t dhkey[32];
+
+ if (*event != BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE) {
+ tester_warn("Failed DHKey generation command");
+ tester_test_failed();
+ return;
+ }
+
+ evt = (void *)(event + 1);
+ if (evt->status) {
+ tester_warn("HCI Generate DHKey complete failed (0x%02x)",
+ evt->status);
+ tester_test_failed();
+ return;
+ }
+
+ util_hexdump('>', evt->dhkey, 32, test_debug, NULL);
+
+
+ util_hexdump('S', keys->remote_sk, 32, test_debug, NULL);
+ util_hexdump('P', keys->local_pk, 64, test_debug, NULL);
+
+ /* Generate DHKey ourself with local public key and remote
+ * private key we got when generated public / private key
+ * pair for BT_HCI_CMD_LE_GENERATE_DHKEY argument.
+ */
+ ecdh_shared_secret(keys->local_pk, keys->remote_sk, dhkey);
+
+ util_hexdump('D', dhkey, 32, test_debug, NULL);
+
+ if (!memcmp(dhkey, evt->dhkey, 32))
+ tester_test_passed();
+ else
+ tester_test_failed();
+}
+
+static void test_le_generate_dhkey_status(const void *data, uint8_t size,
+ void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ tester_warn("Failed to send DHKey gen cmd (0x%02x)", status);
+ tester_test_failed();
+ return;
+ }
+}
+
+static void test_le_generate_dhkey(const void *test_data)
+{
+ struct user_data *user = tester_get_data();
+ struct bt_hci_cmd_le_generate_dhkey cmd;
+ struct le_keys *keys = (void *)test_data;
+
+ ecc_make_key(cmd.remote_pk256, keys->remote_sk);
+
+ /* Unregister handler for META event */
+ bt_hci_unregister(user->hci_ut, 1);
+
+ bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+ test_le_generate_dhkey_complete, keys,
+ NULL);
+
+ if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_GENERATE_DHKEY, &cmd,
+ sizeof(cmd), test_le_generate_dhkey_status,
+ NULL, NULL)) {
+ tester_warn("Failed to send HCI LE Encrypt command");
+ tester_test_failed();
+ return;
+ }
+
+}
+
static void test_inquiry_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -657,6 +928,15 @@ int main(int argc, char *argv[])
test_le_read_white_list_size);
test_hci_local("LE Clear White List", NULL, NULL,
test_le_clear_white_list);
+ test_hci_local("LE Encrypt", NULL, NULL,
+ test_le_encrypt);
+ test_hci_local("LE Rand", NULL, NULL,
+ test_le_rand);
+ test_hci_local("LE Read Local PK", &key_test_data, NULL,
+ test_le_read_local_pk);
+ test_hci_local("LE Generate DHKey", &key_test_data,
+ setup_le_generate_dhkey,
+ test_le_generate_dhkey);
test_hci_local("Inquiry (LIAC)", NULL, NULL, test_inquiry_liac);
diff --git a/tools/hciattach.c b/tools/hciattach.c
index acfa3c7b..5dd97088 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -65,15 +65,16 @@ struct uart_t {
int (*post) (int fd, struct uart_t *u, struct termios *ti);
/* __TIZEN_PATCH__ */
-#ifdef __TI_PATCH__
+#if defined __TIZEN_PATCH__ && defined __TI_PATCH__
uint16_t device_param;
#endif
};
-#ifdef __TI_PATCH__
+#if defined __TIZEN_PATCH__ && defined __TI_PATCH__
int firmware_path = 0;
#endif
+#ifdef __TIZEN_PATCH__
#if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
#define TIOSETBRFPOWER 0x6000
#define BRF_DEEP_SLEEP_OPCODE_BYTE_1 0x0c
@@ -81,6 +82,7 @@ struct uart_t {
#define BRF_DEEP_SLEEP_OPCODE \
(BRF_DEEP_SLEEP_OPCODE_BYTE_1 | (BRF_DEEP_SLEEP_OPCODE_BYTE_2 << 8))
#endif
+#endif
#define FLOW_CTL 0x0001
#define AMP_DEV 0x0002
#define ENABLE_PM 1
@@ -1021,7 +1023,7 @@ static int bcm2035(int fd, struct uart_t *u, struct termios *ti)
memset(resp, 0, sizeof(resp));
/* __TIZEN_PATCH__ */
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x18;
cmd[2] = 0xfc;
@@ -1140,7 +1142,7 @@ struct uart_t uart[] = {
FLOW_CTL, DISABLE_PM, NULL, swave },
/* __TIZEN_PATCH__ */
-#ifdef __TI_PATCH__
+#if defined __TIZEN_PATCH__ && defined __TI_PATCH__
/* Texas Instruments BRF63xx modules */
{ "texas", 0x0000, 0x0000, HCI_UART_LL, 115200,3000000, FLOW_CTL, NULL, texas, NULL/*texas_continue_script*/, BRF_DEEP_SLEEP_OPCODE},
#else
@@ -1258,7 +1260,7 @@ static struct uart_t * get_by_type(char *type)
return NULL;
}
-#ifdef __BROADCOM_PATCH__
+#if defined __TIZEN_PATCH__ && defined __BROADCOM_PATCH__
static int enable_hci(char *dev, struct uart_t *u)
{
int fd, i;
@@ -1307,9 +1309,11 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
unsigned long flags = 0;
/* __TIZEN_PATCH__ */
+#ifdef __TIZEN_PATCH__
#if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
int power;
#endif
+#endif
if (raw)
flags |= 1 << HCI_UART_RAW_DEVICE;
@@ -1333,7 +1337,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
cfmakeraw(&ti);
/* __TIZEN_PATCH__ */
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
ti.c_cflag |= CLOCAL;
if (u->flags & FLOW_CTL)
ti.c_cflag |= CRTSCTS;
@@ -1360,6 +1364,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
}
/* __TIZEN_PATCH__ */
+#ifdef __TIZEN_PATCH__
#if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
/* Power up the BRF chip */
power = 1;
@@ -1368,6 +1373,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
#ifdef __TI_PATCH__
usleep(500000);
#endif
+#endif
if (u->init && u->init(fd, u, &ti) < 0)
goto fail;
@@ -1397,7 +1403,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
goto fail;
}
-#if 0
+#ifndef __TIZEN_PATCH__
if (u->post && u->post(fd, u, &ti) < 0)
goto fail;
#endif
@@ -1417,7 +1423,7 @@ static void usage(void)
printf("Usage:\n");
/* __TIZEN_PATCH__ */
-#ifdef __TI_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__TI_PATCH__)
/* This commented code was present before bluez 5.25 upgrade
* printf("\thciattach [-n] [-p] [-b] [-g device_param] [-r] [-f] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");*/
printf("\thciattach [-n] [-p] [-b] [-g device_param] [-r] [-f]"
@@ -1435,14 +1441,14 @@ static void usage(void)
int main(int argc, char *argv[])
{
struct uart_t *u = NULL;
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
int detach, printpid, raw, opt, i, n, ld, err;
#else
int detach, printpid, opt, i, n, ld, err;
#endif
int to = 10;
int init_speed = 0;
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
int send_break = 0;
#endif
pid_t pid;
@@ -1451,10 +1457,12 @@ int main(int argc, char *argv[])
sigset_t sigs;
char dev[PATH_MAX];
+#ifdef __TIZEN_PATCH__
/* __TIZEN_PATCH__ */
#if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
int power;
#endif
+#endif
#ifdef __TI_PATCH__
uint16_t device_param = 0;
int reset_device = 0;
@@ -1462,17 +1470,17 @@ int main(int argc, char *argv[])
#endif
detach = 1;
printpid = 0;
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
raw = 0;
#endif
-#ifdef __TI_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__TI_PATCH__)
while ((opt=getopt(argc, argv, "bnprft:g:s:l")) != EOF) {
#else
while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) {
#endif
switch(opt) {
case 'b':
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
send_break = 1;
#endif
break;
@@ -1490,7 +1498,7 @@ int main(int argc, char *argv[])
break;
/* __TIZEN_PATCH__ */
-#ifdef __TI_PATCH__
+#if defined(__TIZEN_PATCH__) && defined(__TI_PATCH__)
case 'g':
device_param = (uint16_t)strtol(optarg, NULL, 16);
break;
@@ -1515,7 +1523,7 @@ int main(int argc, char *argv[])
exit(0);
case 'r':
-#ifndef __BROADCOM_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__BROADCOM_PATCH__)
raw = 1;
#endif
break;
@@ -1528,7 +1536,7 @@ int main(int argc, char *argv[])
n = argc - optind;
/* __TIZEN_PATCH__ */
-#ifdef __TI_PATCH__
+#if defined(__TIZEN_PATCH__) && defined(__TI_PATCH__)
if (!reset_device || (reset_device && n < 1))
#endif
if (n < 2) {
@@ -1595,7 +1603,7 @@ int main(int argc, char *argv[])
}
}
/* __TIZEN_PATCH__ */
-#ifdef __TI_PATCH__
+#if defined(__TIZEN_PATCH__) && defined(__TI_PATCH__)
if (reset_device)
{
// Reset row device
@@ -1624,7 +1632,7 @@ int main(int argc, char *argv[])
the hardware's default */
if (init_speed)
u->init_speed = init_speed;
-#ifdef __TI_PATCH__
+#if defined(__TIZEN_PATCH__) && defined(__TI_PATCH__)
/* If user specified a device parameter, use that instead of
the hardware's default */
if (device_param)
@@ -1639,7 +1647,7 @@ int main(int argc, char *argv[])
/* 10 seconds should be enough for initialization */
alarm(to);
bcsp_max_retries = to;
-#ifdef __BROADCOM_PATCH__
+#if defined __TIZEN_PATCH__ && defined __BROADCOM_PATCH__
n = enable_hci(dev, u);
#else
n = init_uart(dev, u, send_break, raw);
@@ -1705,10 +1713,12 @@ int main(int argc, char *argv[])
}
/* __TIZEN_PATCH__ */
+#ifdef __TIZEN_PATCH__
#if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
/* Power down the BRF or BCMchip */
power = 0;
ioctl(n, TIOSETBRFPOWER, &power);
#endif
+#endif
return 0;
}
diff --git a/tools/hciattach.h b/tools/hciattach.h
index 0b7e02e8..ca465942 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -39,10 +39,16 @@
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
#define HCI_UART_ATH3K 5
+#define HCI_UART_INTEL 6
+#define HCI_UART_BCM 7
+#define HCI_UART_QCA 8
#define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1
#define HCI_UART_CREATE_AMP 2
+#define HCI_UART_INIT_PENDING 3
+#define HCI_UART_EXT_CONFIG 4
+#define HCI_UART_VND_DETECT 5
int read_hci_event(int fd, unsigned char *buf, int size);
int set_speed(int fd, struct termios *ti, int speed);
diff --git a/tools/hciattach_sprd.c b/tools/hciattach_sprd.c
index 410a2cf5..6fd2954d 100644
--- a/tools/hciattach_sprd.c
+++ b/tools/hciattach_sprd.c
@@ -473,15 +473,18 @@ void sprd_get_pskey(BT_PSKEY_CONFIG_T * pskey_t) {
memcpy(pskey_t, &pskey, sizeof(BT_PSKEY_CONFIG_T));
}
+#define HCI_HDR_LEN 3
int sprd_config_init(int fd, char *bdaddr, struct termios *ti)
{
int ret = 0,r=0;
unsigned char resp[30] = {0};
BT_PSKEY_CONFIG_T bt_para_tmp;
- uint8 data_tmp[5] = {'a'};
+ uint8 data_tmp[30] = {'a'};
static int index = 0;
uint8 *buf = NULL;
+ uint8 hci_len = 0;
+ uint8 is_expected_hci_evt = 0;
#if 0
char buffer;
int btsleep_fd_sprd = -1;
@@ -563,17 +566,27 @@ int sprd_config_init(int fd, char *bdaddr, struct termios *ti)
++index;
}
-/* if ((data_tmp[0] == 0x04) && (data_tmp[1] == 0x6f)&& (data_tmp[2] == 0x01) &&(data_tmp[3] == 0x0)){*/
- if ((data_tmp[0] == 0x04) && (data_tmp[1] == 0xe)&& (data_tmp[2] == 0xa) &&(data_tmp[3] == 0x1)){
- fprintf(stderr, "read response ok \n");
+ if (index >= 6) {
+ hci_len = data_tmp[2]+HCI_HDR_LEN;
- if (index == 12) {
+ if ((data_tmp[0] == 0x04) && (data_tmp[1] == 0xe) &&
+ (data_tmp[2] == 0xa) &&(data_tmp[3] == 0x1) &&
+ (data_tmp[4] == 0xa0) &&(data_tmp[5] == 0xfc)) {
+ LOGD("read response ok \n");
+ is_expected_hci_evt = 1;
+ } else {
+ LOGD("this is not what we expect HCI evt\n");
+ is_expected_hci_evt = 0;
+ }
+
+ if (index == hci_len) {
index = 0;
memset(data_tmp, 0x0, sizeof(data_tmp));
- break;
+
+ if(is_expected_hci_evt)
+ break;
}
}
}
-
return 0;
}
diff --git a/tools/hciconfig.c b/tools/hciconfig.c
index 6397e715..9029f7d9 100644
--- a/tools/hciconfig.c
+++ b/tools/hciconfig.c
@@ -69,6 +69,7 @@ static void print_dev_list(int ctl, int flags)
if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
perror("Can't get device list");
+ free(dl);
exit(1);
}
@@ -78,6 +79,8 @@ static void print_dev_list(int ctl, int flags)
continue;
print_dev_info(ctl, &di);
}
+
+ free(dl);
}
static void print_pkt_type(struct hci_dev_info *di)
@@ -960,6 +963,8 @@ static void cmd_class(int ctl, int hdev, char *opt)
printf("%s, %s\n", major_devices[cls[1] & 0x1f],
get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));
}
+
+ hci_close_dev(s);
}
static void cmd_voice(int ctl, int hdev, char *opt)
@@ -1020,6 +1025,8 @@ static void cmd_voice(int ctl, int hdev, char *opt)
}
printf("\tAir Coding Format: %s\n", acf[vs & 0x03]);
}
+
+ hci_close_dev(s);
}
static void cmd_delkey(int ctl, int hdev, char *opt)
@@ -1459,6 +1466,8 @@ static void cmd_inq_parms(int ctl, int hdev, char *opt)
printf("\tInquiry interval: %u slots (%.2f ms), window: %u slots (%.2f ms)\n",
interval, (float)interval * 0.625, window, (float)window * 0.625);
}
+
+ hci_close_dev(s);
}
static void cmd_page_parms(int ctl, int hdev, char *opt)
@@ -1530,6 +1539,8 @@ static void cmd_page_parms(int ctl, int hdev, char *opt)
interval, (float)interval * 0.625,
window, (float)window * 0.625);
}
+
+ hci_close_dev(s);
}
static void cmd_page_to(int ctl, int hdev, char *opt)
@@ -1594,6 +1605,8 @@ static void cmd_page_to(int ctl, int hdev, char *opt)
printf("\tPage timeout: %u slots (%.2f ms)\n",
timeout, (float)timeout * 0.625);
}
+
+ hci_close_dev(s);
}
static void cmd_afh_mode(int ctl, int hdev, char *opt)
@@ -1627,6 +1640,8 @@ static void cmd_afh_mode(int ctl, int hdev, char *opt)
print_dev_hdr(&di);
printf("\tAFH mode: %s\n", mode == 1 ? "Enabled" : "Disabled");
}
+
+ hci_close_dev(dd);
}
static void cmd_ssp_mode(int ctl, int hdev, char *opt)
@@ -1661,6 +1676,8 @@ static void cmd_ssp_mode(int ctl, int hdev, char *opt)
printf("\tSimple Pairing mode: %s\n",
mode == 1 ? "Enabled" : "Disabled");
}
+
+ hci_close_dev(dd);
}
static void print_rev_ericsson(int dd)
@@ -1787,6 +1804,9 @@ static void cmd_revision(int ctl, int hdev, char *opt)
printf("\tUnsupported manufacturer\n");
break;
}
+
+ hci_close_dev(dd);
+
return;
}
diff --git a/tools/hcidump.c b/tools/hcidump.c
index 8839eb0b..af8f5925 100644
--- a/tools/hcidump.c
+++ b/tools/hcidump.c
@@ -145,7 +145,8 @@ static int process_frames(int dev, int sock, int fd, unsigned long flags)
struct frame frm;
struct pollfd fds[2];
int nfds = 0;
- char *buf, *ctrl;
+ char *buf;
+ char ctrl[100];
int len, hdr_size = HCIDUMP_HDR_SIZE;
if (sock < 0)
@@ -167,13 +168,6 @@ static int process_frames(int dev, int sock, int fd, unsigned long flags)
dp = (void *) buf;
frm.data = buf + hdr_size;
- ctrl = malloc(100);
- if (!ctrl) {
- free(buf);
- perror("Can't allocate control buffer");
- return -1;
- }
-
if (dev == HCI_DEV_NONE)
printf("system: ");
else
@@ -538,13 +532,13 @@ static int open_socket(int dev, unsigned long flags)
opt = 1;
if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
perror("Can't enable data direction info");
- return -1;
+ goto fail;
}
opt = 1;
if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
perror("Can't enable time stamp");
- return -1;
+ goto fail;
}
/* Setup filter */
@@ -553,7 +547,7 @@ static int open_socket(int dev, unsigned long flags)
hci_filter_all_events(&flt);
if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
perror("Can't set filter");
- return -1;
+ goto fail;
}
/* Bind socket to the HCI device */
@@ -563,10 +557,14 @@ static int open_socket(int dev, unsigned long flags)
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("Can't attach to device hci%d. %s(%d)\n",
dev, strerror(errno), errno);
- return -1;
+ goto fail;
}
return sk;
+
+fail:
+ close(sk);
+ return -1;
}
static struct {
diff --git a/tools/hcitool.c b/tools/hcitool.c
index 02c4ebe1..4a141af5 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -1098,6 +1098,66 @@ static void cmd_epinq(int dev_id, int argc, char **argv)
hci_close_dev(dd);
}
+#ifdef __TIZEN_PATCH__
+/* Send arbitrary ACL data */
+static struct option data_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static const char *data_help =
+ "Usage:\n"
+ "\tcmd <handle> <data>\n"
+ "Example:\n"
+ "\tcmd 0x0064 0x41 0x42 0x43 0x44\n";
+
+static void cmd_data(int dev_id, int argc, char **argv)
+{
+ unsigned char buf[HCI_MAX_ACL_SIZE], *ptr = buf;
+ struct hci_filter flt;
+ int i, opt, len, dd;
+ uint16_t handle;
+
+ for_each_opt(opt, data_options, NULL) {
+ switch (opt) {
+ default:
+ printf("%s", data_help);
+ return;
+ }
+ }
+ helper_arg(2, -1, &argc, &argv, data_help);
+
+ if (dev_id < 0)
+ dev_id = hci_get_route(NULL);
+
+ handle = atoi(argv[0]);
+
+ for (i = 1, len = 0; i < argc && len < (int) sizeof(buf); i++, len++)
+ *ptr++ = (uint8_t) strtol(argv[i], NULL, 16);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Device open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Setup filter */
+ hci_filter_clear(&flt);
+ hci_filter_all_events(&flt);
+ if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+ perror("HCI filter setup failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if (hci_send_data(dd, handle, len, buf) < 0) {
+ perror("Send failed");
+ exit(EXIT_FAILURE);
+ }
+
+ hci_close_dev(dd);
+}
+#endif
+
/* Send arbitrary HCI commands */
static struct option cmd_options[] = {
@@ -3388,6 +3448,9 @@ static struct {
{ "spinq", cmd_spinq, "Start periodic inquiry" },
{ "epinq", cmd_epinq, "Exit periodic inquiry" },
{ "cmd", cmd_cmd, "Submit arbitrary HCI commands" },
+#ifdef __TIZEN_PATCH__
+ { "acl", cmd_data, "Submit arbitrary ACL data" },
+#endif
{ "con", cmd_con, "Display active connections" },
{ "cc", cmd_cc, "Create connection to remote device" },
{ "dc", cmd_dc, "Disconnect from remote device" },
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 7f03591a..945f82ca 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -53,6 +53,8 @@ struct test_data {
uint16_t handle;
uint16_t scid;
uint16_t dcid;
+ int sk;
+ int sk2;
};
struct l2cap_data {
@@ -85,6 +87,11 @@ struct l2cap_data {
bool addr_type_avail;
uint8_t addr_type;
+
+ uint8_t *client_bdaddr;
+ bool server_not_advertising;
+ bool direct_advertising;
+ bool close_one_socket;
};
static void mgmt_debug(const char *str, void *user_data)
@@ -429,6 +436,12 @@ static const struct l2cap_data le_client_connect_success_test_1 = {
.server_psm = 0x0080,
};
+static const struct l2cap_data le_client_connect_adv_success_test_1 = {
+ .client_psm = 0x0080,
+ .server_psm = 0x0080,
+ .direct_advertising = true,
+};
+
static const struct l2cap_data le_client_connect_success_test_2 = {
.client_psm = 0x0080,
.server_psm = 0x0080,
@@ -450,6 +463,30 @@ static const struct l2cap_data le_client_connect_reject_test_2 = {
.addr_type = BDADDR_LE_PUBLIC,
};
+static uint8_t nonexisting_bdaddr[] = {0x00, 0xAA, 0x01, 0x02, 0x03, 0x00};
+static const struct l2cap_data le_client_close_socket_test_1 = {
+ .client_psm = 0x0080,
+ .client_bdaddr = nonexisting_bdaddr,
+};
+
+static const struct l2cap_data le_client_close_socket_test_2 = {
+ .client_psm = 0x0080,
+ .server_not_advertising = true,
+};
+
+static const struct l2cap_data le_client_two_sockets_same_client = {
+ .client_psm = 0x0080,
+ .server_psm = 0x0080,
+ .server_not_advertising = true,
+};
+
+static const struct l2cap_data le_client_two_sockets_close_one = {
+ .client_psm = 0x0080,
+ .server_psm = 0x0080,
+ .server_not_advertising = true,
+ .close_one_socket = true,
+};
+
static const struct l2cap_data le_client_connect_nval_psm_test = {
.client_psm = 0x0080,
.expect_err = ECONNREFUSED,
@@ -462,12 +499,45 @@ static const uint8_t le_connect_req[] = { 0x80, 0x00, /* PSM */
0x05, 0x00, /* Credits */
};
+static const uint8_t le_connect_rsp[] = { 0x40, 0x00, /* DCID */
+ 0xa0, 0x02, /* MTU */
+ 0xe6, 0x00, /* MPS */
+ 0x0a, 0x00, /* Credits */
+ 0x00, 0x00, /* Result */
+};
+
static const struct l2cap_data le_server_success_test = {
.server_psm = 0x0080,
.send_cmd_code = BT_L2CAP_PDU_LE_CONN_REQ,
.send_cmd = le_connect_req,
.send_cmd_len = sizeof(le_connect_req),
.expect_cmd_code = BT_L2CAP_PDU_LE_CONN_RSP,
+ .expect_cmd = le_connect_rsp,
+ .expect_cmd_len = sizeof(le_connect_rsp),
+};
+
+static const uint8_t nval_le_connect_req[] = { 0x80, 0x00, /* PSM */
+ 0x01, 0x00, /* SCID */
+ 0x20, 0x00, /* MTU */
+ 0x20, 0x00, /* MPS */
+ 0x05, 0x00, /* Credits */
+};
+
+static const uint8_t nval_le_connect_rsp[] = { 0x00, 0x00, /* DCID */
+ 0x00, 0x00, /* MTU */
+ 0x00, 0x00, /* MPS */
+ 0x00, 0x00, /* Credits */
+ 0x09, 0x00, /* Result */
+};
+
+static const struct l2cap_data le_server_nval_scid_test = {
+ .server_psm = 0x0080,
+ .send_cmd_code = BT_L2CAP_PDU_LE_CONN_REQ,
+ .send_cmd = nval_le_connect_req,
+ .send_cmd_len = sizeof(nval_le_connect_req),
+ .expect_cmd_code = BT_L2CAP_PDU_LE_CONN_RSP,
+ .expect_cmd = nval_le_connect_rsp,
+ .expect_cmd_len = sizeof(nval_le_connect_rsp),
};
static const struct l2cap_data le_att_client_connect_success_test_1 = {
@@ -534,6 +604,7 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
struct bthost *bthost;
if (status != MGMT_STATUS_SUCCESS) {
@@ -545,10 +616,15 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
bthost = hciemu_client_get_host(data->hciemu);
bthost_set_cmd_complete_cb(bthost, client_cmd_complete, user_data);
- if (data->hciemu_type == HCIEMU_TYPE_LE)
- bthost_set_adv_enable(bthost, 0x01, 0x00);
- else
+
+ if (data->hciemu_type == HCIEMU_TYPE_LE) {
+ if (!l2data || !l2data->server_not_advertising)
+ bthost_set_adv_enable(bthost, 0x01);
+ else
+ tester_setup_complete();
+ } else {
bthost_write_scan_enable(bthost, 0x03);
+ }
}
static void setup_powered_server_callback(uint8_t status, uint16_t length,
@@ -718,6 +794,11 @@ static void setup_powered_client(const void *test_data)
bthost_set_connect_cb(bthost, send_rsp_new_conn, data);
}
+ if (test && test->direct_advertising)
+ mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING,
+ data->mgmt_index, sizeof(param), param,
+ NULL, NULL, NULL);
+
mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
sizeof(param), param, setup_powered_client_callback,
NULL, NULL);
@@ -1013,33 +1094,24 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
return sk;
}
-static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
- uint16_t cid)
+static int connect_l2cap_impl(int sk, const uint8_t *bdaddr,
+ uint8_t bdaddr_type, uint16_t psm, uint16_t cid)
{
- const struct l2cap_data *l2data = data->test_data;
- const uint8_t *client_bdaddr;
struct sockaddr_l2 addr;
int err;
- client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
- if (!client_bdaddr) {
+ if (!bdaddr) {
tester_warn("No client bdaddr");
return -ENODEV;
}
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, (void *) client_bdaddr);
+ bacpy(&addr.l2_bdaddr, (void *) bdaddr);
+ addr.l2_bdaddr_type = bdaddr_type;
addr.l2_psm = htobs(psm);
addr.l2_cid = htobs(cid);
- if (l2data && l2data->addr_type_avail)
- addr.l2_bdaddr_type = l2data->addr_type;
- else if (data->hciemu_type == HCIEMU_TYPE_LE)
- addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
- else
- addr.l2_bdaddr_type = BDADDR_BREDR;
-
err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
err = -errno;
@@ -1051,6 +1123,33 @@ static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
return 0;
}
+static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
+ uint16_t cid)
+{
+ const struct l2cap_data *l2data = data->test_data;
+ const uint8_t *client_bdaddr;
+ uint8_t bdaddr_type;
+
+ if (l2data->client_bdaddr != NULL)
+ client_bdaddr = l2data->client_bdaddr;
+ else
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+
+ if (!client_bdaddr) {
+ tester_warn("No client bdaddr");
+ return -ENODEV;
+ }
+
+ if (l2data && l2data->addr_type_avail)
+ bdaddr_type = l2data->addr_type;
+ else if (data->hciemu_type == HCIEMU_TYPE_LE)
+ bdaddr_type = BDADDR_LE_PUBLIC;
+ else
+ bdaddr_type = BDADDR_BREDR;
+
+ return connect_l2cap_impl(sk, client_bdaddr, bdaddr_type, psm, cid);
+}
+
static void client_l2cap_connect_cb(uint16_t handle, uint16_t cid,
void *user_data)
{
@@ -1060,6 +1159,37 @@ static void client_l2cap_connect_cb(uint16_t handle, uint16_t cid,
data->handle = handle;
}
+static void direct_adv_cmd_complete(uint16_t opcode, const void *param,
+ uint8_t len, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct bt_hci_cmd_le_set_adv_parameters *cp;
+ const uint8_t *expect_bdaddr;
+
+ if (opcode != BT_HCI_CMD_LE_SET_ADV_PARAMETERS)
+ return;
+
+ tester_print("Received advertising parameters HCI command");
+
+ cp = param;
+
+ /* Advertising as client should be direct advertising */
+ if (cp->type != 0x01) {
+ tester_warn("Invalid advertising type");
+ tester_test_failed();
+ return;
+ }
+
+ expect_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+ if (memcmp(expect_bdaddr, cp->direct_addr, 6)) {
+ tester_warn("Invalid direct address in adv params");
+ tester_test_failed();
+ return;
+ }
+
+ tester_test_passed();
+}
+
static void test_connect(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -1078,6 +1208,10 @@ static void test_connect(const void *test_data)
client_l2cap_connect_cb, data);
}
+ if (l2data->direct_advertising)
+ hciemu_add_master_post_command_hook(data->hciemu,
+ direct_adv_cmd_complete, NULL);
+
sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
if (sk < 0) {
tester_test_failed();
@@ -1122,6 +1256,322 @@ static void test_connect_reject(const void *test_data)
close(sk);
}
+static void connect_socket(const uint8_t *client_bdaddr, int *sk_holder,
+ GIOFunc connect_cb)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ GIOChannel *io;
+ int sk;
+
+ sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+ if (sk < 0) {
+ tester_print("Error in create_l2cap_sock");
+ tester_test_failed();
+ return;
+ }
+
+ *sk_holder = sk;
+
+ if (connect_l2cap_impl(sk, client_bdaddr, BDADDR_LE_PUBLIC,
+ l2data->client_psm, l2data->cid) < 0) {
+ tester_print("Error in connect_l2cap_sock");
+ close(sk);
+ tester_test_failed();
+ return;
+ }
+
+ if (connect_cb) {
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ data->io_id = g_io_add_watch(io, G_IO_OUT, connect_cb, NULL);
+
+ g_io_channel_unref(io);
+ }
+
+ tester_print("Connect in progress, sk = %d", sk);
+}
+
+static gboolean test_close_socket_1_part_3(gpointer arg)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Checking whether scan was properly stopped...");
+
+ if (data->sk != -1) {
+ tester_print("Error - scan was not enabled yet");
+ tester_test_failed();
+ return FALSE;
+ }
+
+ if (hciemu_get_master_le_scan_enable(data->hciemu)) {
+ tester_print("Delayed check whether scann is off failed");
+ tester_test_failed();
+ return FALSE;
+ }
+
+ tester_test_passed();
+ return FALSE;
+}
+
+static gboolean test_close_socket_1_part_2(gpointer args)
+{
+ struct test_data *data = tester_get_data();
+ int sk = data->sk;
+
+ tester_print("Will close socket during scan phase...");
+
+ /* We tried to conect to LE device that is not advertising. It
+ * was added to kernel whitelist, and scan was started. We
+ * should be still scanning.
+ */
+ if (!hciemu_get_master_le_scan_enable(data->hciemu)) {
+ tester_print("Error - should be still scanning");
+ tester_test_failed();
+ return FALSE;
+ }
+
+ /* Calling close() should remove device from whitelist, and stop
+ * the scan.
+ */
+ if (close(sk) < 0) {
+ tester_print("Error when closing socket");
+ tester_test_failed();
+ return FALSE;
+ }
+
+ data->sk = -1;
+ /* tester_test_passed will be called when scan is stopped. */
+ return FALSE;
+}
+
+static gboolean test_close_socket_2_part_3(gpointer arg)
+{
+ struct test_data *data = tester_get_data();
+ int sk = data->sk;
+ int err;
+
+ /* Scan should be already over, we're trying to create connection */
+ if (hciemu_get_master_le_scan_enable(data->hciemu)) {
+ tester_print("Error - should no longer scan");
+ tester_test_failed();
+ return FALSE;
+ }
+
+ /* Calling close() should eventually cause CMD_LE_CREATE_CONN_CANCEL */
+ err = close(sk);
+ if (err < 0) {
+ tester_print("Error when closing socket");
+ tester_test_failed();
+ return FALSE;
+ }
+
+ /* CMD_LE_CREATE_CONN_CANCEL will trigger test pass. */
+ return FALSE;
+}
+
+static bool test_close_socket_cc_hook(const void *data, uint16_t len,
+ void *user_data)
+{
+ return false;
+}
+
+static gboolean test_close_socket_2_part_2(gpointer arg)
+{
+ struct test_data *data = tester_get_data();
+ struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+ /* Make sure CMD_LE_CREATE_CONN will not immediately result in
+ * BT_HCI_EVT_CONN_COMPLETE.
+ */
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_EVT,
+ BT_HCI_CMD_LE_CREATE_CONN, test_close_socket_cc_hook, NULL);
+
+ /* Advertise once. After that, kernel should stop scanning, and trigger
+ * BT_HCI_CMD_LE_CREATE_CONN_CANCEL.
+ */
+ bthost_set_adv_enable(bthost, 0x01);
+ bthost_set_adv_enable(bthost, 0x00);
+ return FALSE;
+}
+
+static void test_close_socket_scan_enabled(void)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+
+ if (l2data == &le_client_close_socket_test_1)
+ g_idle_add(test_close_socket_1_part_2, NULL);
+ else if (l2data == &le_client_close_socket_test_2)
+ g_idle_add(test_close_socket_2_part_2, NULL);
+}
+
+static void test_close_socket_scan_disabled(void)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+
+ if (l2data == &le_client_close_socket_test_1)
+ g_idle_add(test_close_socket_1_part_3, NULL);
+ else if (l2data == &le_client_close_socket_test_2)
+ g_idle_add(test_close_socket_2_part_3, NULL);
+}
+
+static void test_close_socket_conn_cancel(void)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+
+ if (l2data == &le_client_close_socket_test_2)
+ tester_test_passed();
+}
+
+static void test_close_socket_router(uint16_t opcode, const void *param,
+ uint8_t length, void *user_data)
+{
+ /* tester_print("HCI Command 0x%04x length %u", opcode, length); */
+ if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE) {
+ const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
+
+ if (scan_params->enable == true)
+ test_close_socket_scan_enabled();
+ else
+ test_close_socket_scan_disabled();
+ } else if (opcode == BT_HCI_CMD_LE_CREATE_CONN_CANCEL) {
+ test_close_socket_conn_cancel();
+ }
+}
+
+static void test_close_socket(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ const uint8_t *client_bdaddr;
+
+ hciemu_add_master_post_command_hook(data->hciemu,
+ test_close_socket_router, data);
+
+ if (l2data->client_bdaddr != NULL)
+ client_bdaddr = l2data->client_bdaddr;
+ else
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+
+ connect_socket(client_bdaddr, &data->sk, NULL);
+}
+
+static uint8_t test_two_sockets_connect_cb_cnt;
+static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ int err, sk_err, sk;
+ socklen_t len = sizeof(sk_err);
+
+ data->io_id = 0;
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+ err = -errno;
+ else
+ err = -sk_err;
+
+ if (err < 0) {
+ tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+ tester_test_failed();
+ return FALSE;
+ }
+
+ tester_print("Successfully connected");
+ test_two_sockets_connect_cb_cnt++;
+
+ if (test_two_sockets_connect_cb_cnt == 2) {
+ close(data->sk);
+ close(data->sk2);
+ tester_test_passed();
+ }
+
+ if (l2data->close_one_socket && test_two_sockets_connect_cb_cnt == 1) {
+ close(data->sk2);
+ tester_test_passed();
+ }
+
+ return FALSE;
+}
+
+static gboolean enable_advertising(gpointer args)
+{
+ struct test_data *data = tester_get_data();
+ struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+ bthost_set_adv_enable(bthost, 0x01);
+ return FALSE;
+}
+
+static void test_connect_two_sockets_part_2(void)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ const uint8_t *client_bdaddr;
+
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+ connect_socket(client_bdaddr, &data->sk2, test_two_sockets_connect_cb);
+
+ if (l2data->close_one_socket) {
+ tester_print("Closing first socket! %d", data->sk);
+ close(data->sk);
+ }
+
+ g_idle_add(enable_advertising, NULL);
+}
+
+static uint8_t test_scan_enable_counter;
+static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
+ uint8_t length, void *user_data)
+{
+ const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
+
+ tester_print("HCI Command 0x%04x length %u", opcode, length);
+ if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE &&
+ scan_params->enable == true) {
+ test_scan_enable_counter++;
+ if (test_scan_enable_counter == 1)
+ test_connect_two_sockets_part_2();
+ else if (test_scan_enable_counter == 2)
+ g_idle_add(enable_advertising, NULL);
+ }
+}
+
+static void test_connect_two_sockets(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ const uint8_t *client_bdaddr;
+
+ test_two_sockets_connect_cb_cnt = 0;
+ test_scan_enable_counter = 0;
+
+ hciemu_add_master_post_command_hook(data->hciemu,
+ test_connect_two_sockets_router, data);
+
+ if (l2data->server_psm) {
+ struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+ if (!l2data->data_len)
+ bthost_add_l2cap_server(bthost, l2data->server_psm,
+ NULL, NULL);
+ }
+
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+ if (l2data->close_one_socket)
+ connect_socket(client_bdaddr, &data->sk, NULL);
+ else
+ connect_socket(client_bdaddr, &data->sk,
+ test_two_sockets_connect_cb);
+}
+
static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -1199,7 +1649,7 @@ static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len,
if (code != l2data->expect_cmd_code) {
tester_warn("Unexpected L2CAP response code (expected 0x%02x)",
l2data->expect_cmd_code);
- goto failed;
+ return;
}
if (code == BT_L2CAP_PDU_CONN_RSP) {
@@ -1428,6 +1878,9 @@ int main(int argc, char *argv[])
test_l2cap_le("L2CAP LE Client - Success",
&le_client_connect_success_test_1,
setup_powered_client, test_connect);
+ test_l2cap_le("L2CAP LE Client, Direct Advertising - Success",
+ &le_client_connect_adv_success_test_1,
+ setup_powered_client, test_connect);
test_l2cap_le("L2CAP LE Client SMP - Success",
&le_client_connect_success_test_2,
setup_powered_client, test_connect);
@@ -1437,11 +1890,34 @@ int main(int argc, char *argv[])
test_l2cap_bredr("L2CAP LE Client - Connection Reject",
&le_client_connect_reject_test_2,
setup_powered_client, test_connect_reject);
+
+ test_l2cap_le("L2CAP LE Client - Close socket 1",
+ &le_client_close_socket_test_1,
+ setup_powered_client,
+ test_close_socket);
+
+ test_l2cap_le("L2CAP LE Client - Close socket 2",
+ &le_client_close_socket_test_2,
+ setup_powered_client,
+ test_close_socket);
+
+ test_l2cap_le("L2CAP LE Client - Open two sockets",
+ &le_client_two_sockets_same_client,
+ setup_powered_client,
+ test_connect_two_sockets);
+
+ test_l2cap_le("L2CAP LE Client - Open two sockets close one",
+ &le_client_two_sockets_close_one,
+ setup_powered_client,
+ test_connect_two_sockets);
+
test_l2cap_le("L2CAP LE Client - Invalid PSM",
&le_client_connect_nval_psm_test,
setup_powered_client, test_connect);
test_l2cap_le("L2CAP LE Server - Success", &le_server_success_test,
setup_powered_server, test_server);
+ test_l2cap_le("L2CAP LE Server - Nval SCID", &le_server_nval_scid_test,
+ setup_powered_server, test_server);
test_l2cap_le("L2CAP LE ATT Client - Success",
diff --git a/tools/l2test.c b/tools/l2test.c
index 83c5cbde..50c4dc1b 100644
--- a/tools/l2test.c
+++ b/tools/l2test.c
@@ -119,7 +119,13 @@ static unsigned long send_delay = 0;
/* Default delay before receiving */
static unsigned long recv_delay = 0;
-static char *filename = NULL;
+/* Default delay before disconnecting */
+static unsigned long disc_delay = 0;
+
+/* Initial sequence value when sending frames */
+static int seq_start = 0;
+
+static const char *filename = NULL;
static int rfcmode = 0;
static int master = 0;
@@ -597,6 +603,7 @@ static void do_listen(void (*handler)(int sk))
if (socktype == SOCK_DGRAM) {
handler(sk);
+ close(sk);
return;
}
@@ -649,7 +656,6 @@ static void do_listen(void (*handler)(int sk))
continue;
}
/* Child */
- close(sk);
/* Set receive buffer size */
if (rcvbuf && setsockopt(nsk, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
@@ -774,6 +780,7 @@ static void do_listen(void (*handler)(int sk))
}
handler(nsk);
+ close(sk);
syslog(LOG_INFO, "Disconnect: %m");
exit(0);
@@ -979,13 +986,18 @@ static void do_send(int sk)
sent += len;
size -= len;
}
+
+ close(fd);
return;
} else {
for (i = 6; i < data_size; i++)
buf[i] = 0x7f;
}
- seq = 0;
+ if (!count && send_delay)
+ usleep(send_delay);
+
+ seq = seq_start;
while ((num_frames == -1) || (num_frames-- > 0)) {
put_le32(seq, buf);
put_le16(data_size, buf + 4);
@@ -1008,7 +1020,8 @@ static void do_send(int sk)
size -= len;
}
- if (num_frames && send_delay && count && !(seq % count))
+ if (num_frames && send_delay && count &&
+ !(seq % (count + seq_start)))
usleep(send_delay);
}
}
@@ -1017,6 +1030,9 @@ static void send_mode(int sk)
{
do_send(sk);
+ if (disc_delay)
+ usleep(disc_delay);
+
syslog(LOG_INFO, "Closing channel ...");
if (shutdown(sk, SHUT_RDWR) < 0)
syslog(LOG_INFO, "Close failed: %m");
@@ -1450,11 +1466,9 @@ static void usage(void)
"\t-m multiple connects\n"
"\t-p trigger dedicated bonding\n"
#ifdef __TIZEN_PATCH__
- "\t-z information request\n"
- "\t-o configuration request\n");
-#else
- "\t-z information request\n");
+ "\t-o configuration request\n"
#endif
+ "\t-z information request\n");
printf("Options:\n"
"\t[-b bytes] [-i device] [-P psm] [-J cid]\n"
@@ -1466,6 +1480,7 @@ static void usage(void)
"\t[-C num] send num frames before delay (default = 1)\n"
"\t[-D milliseconds] delay after sending num frames (default = 0)\n"
"\t[-K milliseconds] delay before receiving (default = 0)\n"
+ "\t[-g milliseconds] delay before disconnecting (default = 0)\n"
"\t[-X mode] l2cap mode (help for list, default = basic)\n"
"\t[-a policy] chan policy (help for list, default = bredr)\n"
"\t[-F fcs] use CRC16 check (default = 1)\n"
@@ -1481,12 +1496,11 @@ static void usage(void)
"\t[-S] secure connection\n"
"\t[-M] become master\n"
"\t[-T] enable timestamps\n"
-#ifdef __TIZEN_PATCH__
"\t[-V type] address type (help for list, default = bredr)\n"
- "\t[-e DCID] destination CID\n");
-#else
- "\t[-V type] address type (help for list, default = bredr)\n");
+#ifdef __TIZEN_PATCH__
+ "\t[-f DCID] destination CID\n"
#endif
+ "\t[-e seq] initial sequence value (default = 0)\n");
}
int main(int argc, char *argv[])
@@ -1497,11 +1511,11 @@ int main(int argc, char *argv[])
bacpy(&bdaddr, BDADDR_ANY);
#ifdef __TIZEN_PATCH__
- while ((opt = getopt(argc, argv, "rdscouwmntqxyzpb:a:"
- "i:P:I:O:J:B:N:L:W:C:D:X:F:Q:Z:Y:H:K:V:e:RUGAESMT")) != EOF) {
+ while ((opt = getopt(argc, argv, "a:b:cde:f:g:i:mnopqrstuwxyz"
+ "AB:C:D:EF:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
#else
- while ((opt = getopt(argc, argv, "rdscuwmntqxyzpb:a:"
- "i:P:I:O:J:B:N:L:W:C:D:X:F:Q:Z:Y:H:K:V:RUGAESMT")) != EOF) {
+ while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnpqrstuwxyz"
+ "AB:C:D:EF:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
#endif
switch (opt) {
case 'r':
@@ -1607,7 +1621,7 @@ int main(int argc, char *argv[])
break;
case 'B':
- filename = strdup(optarg);
+ filename = optarg;
break;
case 'N':
@@ -1714,12 +1728,22 @@ int main(int argc, char *argv[])
}
break;
+
#ifdef __TIZEN_PATCH__
- case 'e':
+ case 'f':
dcid = atoi(optarg);
printf("dcid %d", dcid);
break;
#endif
+
+ case 'e':
+ seq_start = atoi(optarg);
+ break;
+
+ case 'g':
+ disc_delay = atoi(optarg) * 1000;
+ break;
+
default:
usage();
exit(1);
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index d9970103..494d436e 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -79,7 +79,7 @@ static void read_version_callback(uint8_t status, uint16_t length,
const struct mgmt_rp_read_version *rp = param;
tester_print("Read Version callback");
- tester_print(" Status: 0x%02x", status);
+ tester_print(" Status: %s (0x%02x)", mgmt_errstr(status), status);
if (status || !param) {
tester_pre_setup_failed();
@@ -97,7 +97,7 @@ static void read_commands_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
tester_print("Read Commands callback");
- tester_print(" Status: 0x%02x", status);
+ tester_print(" Status: %s (0x%02x)", mgmt_errstr(status), status);
if (status || !param) {
tester_pre_setup_failed();
@@ -116,7 +116,7 @@ static void read_info_callback(uint8_t status, uint16_t length,
struct bthost *bthost;
tester_print("Read Info callback");
- tester_print(" Status: 0x%02x", status);
+ tester_print(" Status: %s (0x%02x)", mgmt_errstr(status), status);
if (status || !param) {
tester_pre_setup_failed();
@@ -216,7 +216,7 @@ static void read_index_list_callback(uint8_t status, uint16_t length,
struct test_data *data = tester_get_data();
tester_print("Read Index List callback");
- tester_print(" Status: 0x%02x", status);
+ tester_print(" Status: %s (0x%02x)", mgmt_errstr(status), status);
if (status || !param) {
tester_pre_setup_failed();
@@ -300,7 +300,7 @@ static void test_condition_complete(struct test_data *data)
tester_test_passed();
}
-#define test_bredrle(name, data, setup, func) \
+#define test_bredrle_full(name, data, setup, func, timeout) \
do { \
struct test_data *user; \
user = malloc(sizeof(struct test_data)); \
@@ -316,9 +316,12 @@ static void test_condition_complete(struct test_data *data)
user->unmet_conditions = 0; \
tester_add_full(name, data, \
test_pre_setup, test_setup, func, NULL, \
- test_post_teardown, 2, user, free); \
+ test_post_teardown, timeout, user, free); \
} while (0)
+#define test_bredrle(name, data, setup, func) \
+ test_bredrle_full(name, data, setup, func, 2)
+
#define test_bredr20(name, data, setup, func) \
do { \
struct test_data *user; \
@@ -328,7 +331,7 @@ static void test_condition_complete(struct test_data *data)
user->hciemu_type = HCIEMU_TYPE_LEGACY; \
user->test_setup = setup; \
user->test_data = data; \
- user->expected_version = 0x04; \
+ user->expected_version = 0x03; \
user->expected_manufacturer = 0x003f; \
user->expected_supported_settings = 0x000010bf; \
user->initial_settings = 0x00000080; \
@@ -429,6 +432,9 @@ struct generic_data {
bool force_power_off;
bool addr_type_avail;
uint8_t addr_type;
+ bool set_adv;
+ const uint8_t *adv_data;
+ uint8_t adv_data_len;
};
static const char dummy_data[] = { 0x00 };
@@ -578,6 +584,22 @@ static const struct generic_data set_powered_on_invalid_index_test = {
.expect_status = MGMT_STATUS_INVALID_INDEX,
};
+static uint16_t settings_powered_advertising_privacy[] = {
+ MGMT_OP_SET_PRIVACY,
+ MGMT_OP_SET_ADVERTISING,
+ MGMT_OP_SET_POWERED, 0 };
+
+static const char set_adv_off_param[] = { 0x00 };
+
+static const struct generic_data set_powered_on_privacy_adv_test = {
+ .setup_settings = settings_powered_advertising_privacy,
+ .send_opcode = MGMT_OP_SET_ADVERTISING,
+ .send_param = set_adv_off_param,
+ .send_len = sizeof(set_adv_off_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_ignore_param = true,
+};
+
static const uint16_t settings_powered[] = { MGMT_OP_SET_POWERED, 0 };
static const char set_powered_off_param[] = { 0x00 };
@@ -1542,6 +1564,7 @@ static const struct generic_data set_hs_on_invalid_index_test = {
static uint16_t settings_le[] = { MGMT_OP_SET_LE, 0 };
static const char set_le_on_param[] = { 0x01 };
+static const char set_le_off_param[] = { 0x00 };
static const char set_le_invalid_param[] = { 0x02 };
static const char set_le_garbage_param[] = { 0x01, 0x00 };
static const char set_le_settings_param_1[] = { 0x80, 0x02, 0x00, 0x00 };
@@ -1620,6 +1643,7 @@ static const char set_adv_on_param[] = { 0x01 };
static const char set_adv_settings_param_1[] = { 0x80, 0x06, 0x00, 0x00 };
static const char set_adv_settings_param_2[] = { 0x81, 0x06, 0x00, 0x00 };
static const char set_adv_on_set_adv_enable_param[] = { 0x01 };
+static const char set_adv_on_set_adv_disable_param[] = { 0x00 };
static const struct generic_data set_adv_on_success_test_1 = {
.setup_settings = settings_le,
@@ -1849,7 +1873,7 @@ static const struct generic_data start_discovery_valid_param_test_2 = {
};
static const struct generic_data start_discovery_valid_param_power_off_1 = {
- .setup_settings = settings_powered_le,
+ .setup_settings = settings_le,
.send_opcode = MGMT_OP_START_DISCOVERY,
.send_param = start_discovery_bredrle_param,
.send_len = sizeof(start_discovery_bredrle_param),
@@ -1865,7 +1889,6 @@ static const char stop_discovery_valid_hci[] = { 0x00, 0x00 };
static const char stop_discovery_evt[] = { 0x07, 0x00 };
static const char stop_discovery_bredr_param[] = { 0x01 };
static const char stop_discovery_bredr_discovering[] = { 0x01, 0x00 };
-static const char stop_discovery_inq_param[] = { 0x33, 0x8b, 0x9e, 0x08, 0x00 };
static const struct generic_data stop_discovery_success_test_1 = {
.setup_settings = settings_powered_le,
@@ -3656,6 +3679,24 @@ static const struct generic_data add_device_fail_3 = {
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
+static const uint8_t add_device_nval_4[] = {
+ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
+ 0x02,
+ 0x02,
+};
+static const uint8_t add_device_rsp_4[] = {
+ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
+ 0x02,
+};
+static const struct generic_data add_device_fail_4 = {
+ .send_opcode = MGMT_OP_ADD_DEVICE,
+ .send_param = add_device_nval_4,
+ .send_len = sizeof(add_device_nval_4),
+ .expect_param = add_device_rsp_4,
+ .expect_len = sizeof(add_device_rsp_4),
+ .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
static const uint8_t add_device_success_param_1[] = {
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
0x00,
@@ -3770,6 +3811,19 @@ static const struct generic_data remove_device_fail_2 = {
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
+static const uint8_t remove_device_param_3[] = {
+ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
+ 0x02,
+};
+static const struct generic_data remove_device_fail_3 = {
+ .send_opcode = MGMT_OP_REMOVE_DEVICE,
+ .send_param = remove_device_param_3,
+ .send_len = sizeof(remove_device_param_3),
+ .expect_param = remove_device_param_3,
+ .expect_len = sizeof(remove_device_param_3),
+ .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
static const struct generic_data remove_device_success_1 = {
.send_opcode = MGMT_OP_REMOVE_DEVICE,
.send_param = remove_device_param_1,
@@ -3808,16 +3862,12 @@ static const struct generic_data remove_device_success_3 = {
.expect_alt_ev = MGMT_EV_DEVICE_REMOVED,
.expect_alt_ev_param = remove_device_param_1,
.expect_alt_ev_len = sizeof(remove_device_param_1),
- .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
- .expect_hci_param = set_connectable_off_scan_enable_param,
- .expect_hci_len = sizeof(set_connectable_off_scan_enable_param),
};
static const uint8_t remove_device_param_2[] = {
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
0x01,
};
-static const uint8_t set_le_scan_off[] = { 0x00, 0x00 };
static const struct generic_data remove_device_success_4 = {
.setup_settings = settings_powered,
.send_opcode = MGMT_OP_REMOVE_DEVICE,
@@ -3829,9 +3879,6 @@ static const struct generic_data remove_device_success_4 = {
.expect_alt_ev = MGMT_EV_DEVICE_REMOVED,
.expect_alt_ev_param = remove_device_param_2,
.expect_alt_ev_len = sizeof(remove_device_param_2),
- .expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
- .expect_hci_param = set_le_scan_off,
- .expect_hci_len = sizeof(set_le_scan_off),
};
static const struct generic_data remove_device_success_5 = {
@@ -3844,9 +3891,6 @@ static const struct generic_data remove_device_success_5 = {
.expect_alt_ev = MGMT_EV_DEVICE_REMOVED,
.expect_alt_ev_param = remove_device_param_2,
.expect_alt_ev_len = sizeof(remove_device_param_2),
- .expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
- .expect_hci_param = set_le_scan_off,
- .expect_hci_len = sizeof(set_le_scan_off),
};
static const struct generic_data read_adv_features_invalid_param_test = {
@@ -3862,121 +3906,247 @@ static const struct generic_data read_adv_features_invalid_index_test = {
.expect_status = MGMT_STATUS_INVALID_INDEX,
};
-static const uint8_t add_advertising_param_1[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_2[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x03, 0x19, 0x40, 0x03,
- 0x05, 0x03, 0x0d, 0x18, 0x0f, 0x18,
-};
-
-static const uint8_t add_advertising_param_3[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_4[] = {
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+static const uint8_t read_adv_features_rsp_1[] = {
+ 0x1f, 0x00, 0x00, 0x00, /* supported flags */
+ 0x1f, /* max_adv_data_len */
+ 0x1f, /* max_scan_rsp_len */
+ 0x05, /* max_instances */
+ 0x00, /* num_instances */
};
-static const uint8_t add_advertising_param_5[] = {
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_6[] = {
- 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+static const struct generic_data read_adv_features_success_1 = {
+ .send_opcode = MGMT_OP_READ_ADV_FEATURES,
+ .expect_param = read_adv_features_rsp_1,
+ .expect_len = sizeof(read_adv_features_rsp_1),
+ .expect_status = MGMT_STATUS_SUCCESS,
};
-static const uint8_t add_advertising_param_7[] = {
- 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+static const uint8_t read_adv_features_rsp_2[] = {
+ 0x1f, 0x00, 0x00, 0x00, /* supported flags */
+ 0x1f, /* max_adv_data_len */
+ 0x1f, /* max_scan_rsp_len */
+ 0x05, /* max_instances */
+ 0x01, /* num_instances */
+ 0x01, /* instance identifiers */
};
-static const uint8_t add_advertising_param_8[] = {
- 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+static const struct generic_data read_adv_features_success_2 = {
+ .send_opcode = MGMT_OP_READ_ADV_FEATURES,
+ .expect_param = read_adv_features_rsp_2,
+ .expect_len = sizeof(read_adv_features_rsp_2),
+ .expect_status = MGMT_STATUS_SUCCESS,
+};
+
+/* simple add advertising command */
+static const uint8_t add_advertising_param_uuid[] = {
+ 0x01, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration: default */
+ 0x00, 0x00, /* timeout: none */
+ 0x09, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+};
+
+/* add advertising with scan response data */
+static const uint8_t add_advertising_param_scanrsp[] = {
+ /* instance, flags, duration, timeout, adv data len: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0x0a, /* scan rsp len */
+ /* adv data: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* scan rsp data: */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x0f, 0x18, /* battery service */
+};
+
+/* add advertising with timeout */
+static const uint8_t add_advertising_param_timeout[] = {
+ /* instance, flags, duration: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, /* timeout: 5 seconds */
+ /* adv data: same as before */
+ 0x09, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with connectable flag */
+static const uint8_t add_advertising_param_connectable[] = {
+ 0x01, /* adv instance */
+ 0x01, 0x00, 0x00, 0x00, /* flags: connectable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with general discoverable flag */
+static const uint8_t add_advertising_param_general_discov[] = {
+ 0x01, /* adv instance */
+ 0x02, 0x00, 0x00, 0x00, /* flags: general discoverable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with limited discoverable flag */
+static const uint8_t add_advertising_param_limited_discov[] = {
+ 0x01, /* adv instance */
+ 0x04, 0x00, 0x00, 0x00, /* flags: limited discoverable */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with managed flags */
+static const uint8_t add_advertising_param_managed[] = {
+ 0x01, /* adv instance */
+ 0x08, 0x00, 0x00, 0x00, /* flags: managed flags */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with tx power flag */
+static const uint8_t add_advertising_param_txpwr[] = {
+ 0x01, /* adv instance */
+ 0x10, 0x00, 0x00, 0x00, /* flags: tx power */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising command for a second instance */
+static const uint8_t add_advertising_param_test2[] = {
+ 0x02, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration: default */
+ 0x01, 0x00, /* timeout: 1 second */
+ 0x07, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x32, /* "test2" */
+};
+
+static const uint8_t advertising_instance1_param[] = {
+ 0x01,
};
-static const uint8_t advertising_instance_param[] = {
- 0x01,
+static const uint8_t advertising_instance2_param[] = {
+ 0x02,
};
-static const uint8_t set_adv_data_1[] = {
- 0x09, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+static const uint8_t set_adv_data_uuid[] = {
+ /* adv data len */
+ 0x09,
+ /* advertise heart rate monitor and manufacturer specific data */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
};
-static const uint8_t set_adv_data_2[] = {
- 0x0c, 0x02, 0x01, 0x04, 0x03, 0x03, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_test1[] = {
+ 0x07, /* adv data len */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x31, /* "test1" */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};
-static const uint8_t set_adv_data_3[] = {
- 0x06, 0x05, 0x08, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_test2[] = {
+ 0x07, /* adv data len */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x32, /* "test2" */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};
-static const uint8_t set_adv_data_4[] = {
- 0x03, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_txpwr[] = {
+ 0x03, /* adv data len */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_5[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_general_discov[] = {
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-static const uint8_t set_adv_data_6[] = {
- 0x0c, 0x02, 0x01, 0x01, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_limited_discov[] = {
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x01, /* limited discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_7[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_uuid_txpwr[] = {
+ 0x0c, /* adv data len */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_8[] = {
- 0x0c, 0x02, 0x0a, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_scan_rsp_uuid[] = {
+ 0x0a, /* scan rsp data len */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, 0x0f, 0x18, /* heart rate monitor, battery service */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_scan_rsp_1[] = {
- 0x0a, 0x03, 0x19, 0x40, 0x03, 0x05, 0x03, 0x0d, 0x18, 0x0f,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00,
};
static const uint8_t add_advertising_invalid_param_1[] = {
@@ -4050,8 +4220,8 @@ static const uint8_t add_advertising_invalid_param_10[] = {
static const struct generic_data add_advertising_fail_1 = {
.setup_settings = settings_powered,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
.expect_status = MGMT_STATUS_REJECTED,
};
@@ -4138,32 +4308,32 @@ static const struct generic_data add_advertising_fail_11 = {
static const struct generic_data add_advertising_fail_12 = {
.setup_settings = settings_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_3,
- .send_len = sizeof(add_advertising_param_3),
+ .send_param = add_advertising_param_timeout,
+ .send_len = sizeof(add_advertising_param_timeout),
.expect_status = MGMT_STATUS_REJECTED,
};
static const struct generic_data add_advertising_success_1 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_1,
- .expect_hci_len = sizeof(set_adv_data_1),
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
};
static const char set_powered_adv_instance_settings_param[] = {
0x81, 0x02, 0x00, 0x00,
};
-static const struct generic_data add_advertising_success_2 = {
+static const struct generic_data add_advertising_success_pwron_data = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_on_param,
.send_len = sizeof(set_powered_on_param),
@@ -4171,11 +4341,11 @@ static const struct generic_data add_advertising_success_2 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_3,
- .expect_hci_len = sizeof(set_adv_data_3),
+ .expect_hci_param = set_adv_data_test1,
+ .expect_hci_len = sizeof(set_adv_data_test1),
};
-static const struct generic_data add_advertising_success_3 = {
+static const struct generic_data add_advertising_success_pwron_enabled = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_on_param,
.send_len = sizeof(set_powered_on_param),
@@ -4195,12 +4365,10 @@ static const struct generic_data add_advertising_success_4 = {
.expect_param = set_adv_settings_param_2,
.expect_len = sizeof(set_adv_settings_param_2),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_4,
- .expect_hci_len = sizeof(set_adv_data_4),
+ .expect_hci_param = set_adv_data_txpwr,
+ .expect_hci_len = sizeof(set_adv_data_txpwr),
};
-static const char set_adv_off_param[] = { 0x00 };
-
static const struct generic_data add_advertising_success_5 = {
.send_opcode = MGMT_OP_SET_ADVERTISING,
.send_param = set_adv_off_param,
@@ -4209,49 +4377,49 @@ static const struct generic_data add_advertising_success_5 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_3,
- .expect_hci_len = sizeof(set_adv_data_3),
+ .expect_hci_param = set_adv_data_test1,
+ .expect_hci_len = sizeof(set_adv_data_test1),
};
static const struct generic_data add_advertising_success_6 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_1,
- .expect_hci_len = sizeof(set_adv_data_1),
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
};
static const struct generic_data add_advertising_success_7 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_RSP_DATA,
- .expect_hci_param = set_scan_rsp_1,
- .expect_hci_len = sizeof(set_scan_rsp_1),
+ .expect_hci_param = set_scan_rsp_uuid,
+ .expect_hci_len = sizeof(set_scan_rsp_uuid),
};
static const struct generic_data add_advertising_success_8 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_4,
- .send_len = sizeof(add_advertising_param_4),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_connectable,
+ .send_len = sizeof(add_advertising_param_connectable),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_on_adv_param,
@@ -4261,53 +4429,53 @@ static const struct generic_data add_advertising_success_8 = {
static const struct generic_data add_advertising_success_9 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_5,
- .send_len = sizeof(add_advertising_param_5),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_general_discov,
+ .send_len = sizeof(add_advertising_param_general_discov),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_5,
- .expect_hci_len = sizeof(set_adv_data_5),
+ .expect_hci_param = set_adv_data_general_discov,
+ .expect_hci_len = sizeof(set_adv_data_general_discov),
};
static const struct generic_data add_advertising_success_10 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_6,
- .send_len = sizeof(add_advertising_param_6),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_limited_discov,
+ .send_len = sizeof(add_advertising_param_limited_discov),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_6,
- .expect_hci_len = sizeof(set_adv_data_6),
+ .expect_hci_param = set_adv_data_limited_discov,
+ .expect_hci_len = sizeof(set_adv_data_limited_discov),
};
static const struct generic_data add_advertising_success_11 = {
.setup_settings = settings_powered_le_discoverable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_7,
- .send_len = sizeof(add_advertising_param_7),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_managed,
+ .send_len = sizeof(add_advertising_param_managed),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_7,
- .expect_hci_len = sizeof(set_adv_data_7),
+ .expect_hci_param = set_adv_data_general_discov,
+ .expect_hci_len = sizeof(set_adv_data_general_discov),
};
static const struct generic_data add_advertising_success_12 = {
.setup_settings = settings_powered_le_discoverable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_8,
- .send_len = sizeof(add_advertising_param_8),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_txpwr,
+ .send_len = sizeof(add_advertising_param_txpwr),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_8,
- .expect_hci_len = sizeof(set_adv_data_8),
+ .expect_hci_param = set_adv_data_uuid_txpwr,
+ .expect_hci_len = sizeof(set_adv_data_uuid_txpwr),
};
static uint16_t settings_powered_le_connectable[] = {
@@ -4329,10 +4497,10 @@ static uint8_t set_connectable_off_scan_adv_param[] = {
static const struct generic_data add_advertising_success_13 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_off_scan_adv_param,
@@ -4342,10 +4510,10 @@ static const struct generic_data add_advertising_success_13 = {
static const struct generic_data add_advertising_success_14 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_off_adv_param,
@@ -4355,10 +4523,10 @@ static const struct generic_data add_advertising_success_14 = {
static const struct generic_data add_advertising_success_15 = {
.setup_settings = settings_powered_le_connectable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_on_adv_param,
@@ -4396,7 +4564,7 @@ static const char set_powered_off_le_settings_param[] = {
0x80, 0x02, 0x00, 0x00
};
-static const struct generic_data add_advertising_timeout_power_off = {
+static const struct generic_data add_advertising_power_off = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_off_param,
.send_len = sizeof(set_powered_off_param),
@@ -4404,8 +4572,43 @@ static const struct generic_data add_advertising_timeout_power_off = {
.expect_param = set_powered_off_le_settings_param,
.expect_len = sizeof(set_powered_off_le_settings_param),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+};
+
+static const char set_le_settings_param_off[] = { 0x81, 0x00, 0x00, 0x00 };
+
+static const struct generic_data add_advertising_le_off = {
+ .send_opcode = MGMT_OP_SET_LE,
+ .send_param = set_le_off_param,
+ .send_len = sizeof(set_le_off_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = set_le_settings_param_off,
+ .expect_len = sizeof(set_le_settings_param_off),
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+};
+
+static const struct generic_data add_advertising_success_18 = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
+};
+
+static const struct generic_data add_advertising_timeout_expired = {
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+ .expect_hci_param = set_adv_on_set_adv_disable_param,
+ .expect_hci_len = sizeof(set_adv_on_set_adv_disable_param),
};
static const uint8_t remove_advertising_param_1[] = {
@@ -4431,8 +4634,8 @@ static const struct generic_data remove_advertising_success_1 = {
.expect_param = remove_advertising_param_1,
.expect_len = sizeof(remove_advertising_param_1),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
.expect_hci_param = set_adv_off_param,
.expect_hci_len = sizeof(set_adv_off_param),
@@ -4443,16 +4646,91 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
.expect_hci_param = set_adv_off_param,
.expect_hci_len = sizeof(set_adv_off_param),
};
+static const struct generic_data multi_advertising_switch = {
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_test2,
+ .expect_hci_len = sizeof(set_adv_data_test2),
+};
+
+static const struct generic_data multi_advertising_add_second = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_test2,
+ .send_len = sizeof(add_advertising_param_test2),
+ .expect_param = advertising_instance2_param,
+ .expect_len = sizeof(advertising_instance2_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
+ .expect_alt_ev_param = advertising_instance2_param,
+ .expect_alt_ev_len = sizeof(advertising_instance2_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_test2,
+ .expect_hci_len = sizeof(set_adv_data_test2),
+};
+
+/* based on G-Tag ADV_DATA */
+static const uint8_t adv_data_invalid_significant_len[] = { 0x02, 0x01, 0x06,
+ 0x0d, 0xff, 0x80, 0x01, 0x02, 0x15, 0x12, 0x34, 0x80, 0x91,
+ 0xd0, 0xf2, 0xbb, 0xc5, 0x03, 0x02, 0x0f, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const char device_found_valid[] = { 0x00, 0x00, 0x01, 0x01, 0xaa, 0x00,
+ 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x02, 0x01,
+ 0x06, 0x0d, 0xff, 0x80, 0x01, 0x02, 0x15, 0x12, 0x34, 0x80,
+ 0x91, 0xd0, 0xf2, 0xbb, 0xc5, 0x03, 0x02, 0x0f, 0x18 };
+
+static const struct generic_data device_found_gtag = {
+ .setup_settings = settings_powered_le,
+ .send_opcode = MGMT_OP_START_DISCOVERY,
+ .send_param = start_discovery_le_param,
+ .send_len = sizeof(start_discovery_le_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = start_discovery_le_param,
+ .expect_len = sizeof(start_discovery_le_param),
+ .expect_alt_ev = MGMT_EV_DEVICE_FOUND,
+ .expect_alt_ev_param = device_found_valid,
+ .expect_alt_ev_len = sizeof(device_found_valid),
+ .set_adv = true,
+ .adv_data_len = sizeof(adv_data_invalid_significant_len),
+ .adv_data = adv_data_invalid_significant_len,
+};
+
+static const uint8_t adv_data_invalid_field_len[] = { 0x02, 0x01, 0x01,
+ 0x05, 0x09, 0x74, 0x65, 0x73, 0x74,
+ 0xa0, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05};
+
+static const char device_found_valid2[] = { 0x00, 0x00, 0x01, 0x01, 0xaa, 0x00,
+ 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x01,
+ 0x01, 0x05, 0x09, 0x74, 0x65, 0x73, 0x74};
+
+static const struct generic_data device_found_invalid_field = {
+ .setup_settings = settings_powered_le,
+ .send_opcode = MGMT_OP_START_DISCOVERY,
+ .send_param = start_discovery_le_param,
+ .send_len = sizeof(start_discovery_le_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = start_discovery_le_param,
+ .expect_len = sizeof(start_discovery_le_param),
+ .expect_alt_ev = MGMT_EV_DEVICE_FOUND,
+ .expect_alt_ev_param = device_found_valid2,
+ .expect_alt_ev_len = sizeof(device_found_valid2),
+ .set_adv = true,
+ .adv_data_len = sizeof(adv_data_invalid_field_len),
+ .adv_data = adv_data_invalid_field_len,
+};
+
static const struct generic_data read_local_oob_not_powered_test = {
.send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
.expect_status = MGMT_STATUS_NOT_POWERED,
@@ -4506,14 +4784,16 @@ static void client_cmd_complete(uint16_t opcode, uint8_t status,
switch (opcode) {
case BT_HCI_CMD_WRITE_SCAN_ENABLE:
case BT_HCI_CMD_LE_SET_ADV_ENABLE:
- tester_print("Client set connectable status 0x%02x", status);
+ tester_print("Client set connectable: %s (0x%02x)",
+ mgmt_errstr(status), status);
if (!status && test->client_enable_ssp) {
bthost_write_ssp_mode(bthost, 0x01);
return;
}
break;
case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
- tester_print("Client enable SSP status 0x%02x", status);
+ tester_print("Client enable SSP: %s (0x%02x)",
+ mgmt_errstr(status), status);
break;
default:
return;
@@ -4533,7 +4813,7 @@ static void setup_bthost(void)
bthost = hciemu_client_get_host(data->hciemu);
bthost_set_cmd_complete_cb(bthost, client_cmd_complete, data);
if (data->hciemu_type == HCIEMU_TYPE_LE)
- bthost_set_adv_enable(bthost, 0x01, 0x00);
+ bthost_set_adv_enable(bthost, 0x01);
else
bthost_write_scan_enable(bthost, 0x03);
}
@@ -4825,7 +5105,7 @@ static void setup_add_device(const void *test_data)
const unsigned char *add_param;
size_t add_param_len;
- tester_print("Powering on controller (with added device))");
+ tester_print("Powering on controller (with added device)");
if (data->hciemu_type == HCIEMU_TYPE_LE) {
add_param = add_device_success_param_2;
@@ -4846,36 +5126,48 @@ static void setup_add_device(const void *test_data)
static void setup_add_advertising_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
+ struct mgmt_rp_add_advertising *rp =
+ (struct mgmt_rp_add_advertising *) param;
+
if (status != MGMT_STATUS_SUCCESS) {
tester_setup_failed();
return;
}
- tester_print("Add Advertising setup complete");
+ tester_print("Add Advertising setup complete (instance %d)",
+ rp->instance);
setup_bthost();
}
+#define TESTER_ADD_ADV_DATA_LEN 7
+
+static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp,
+ uint8_t instance)
+{
+ memset(cp, 0, sizeof(*cp));
+ cp->instance = instance;
+ cp->adv_data_len = TESTER_ADD_ADV_DATA_LEN;
+ cp->data[0] = TESTER_ADD_ADV_DATA_LEN - 1; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
+ cp->data[3] = 'e';
+ cp->data[4] = 's';
+ cp->data[5] = 't';
+ cp->data[6] = '0' + instance;
+}
+
static void setup_add_advertising_not_powered(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };
tester_print("Adding advertising instance while unpowered");
cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp, 1);
mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -4891,22 +5183,13 @@ static void setup_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };
- tester_print("Adding advertising instance while unpowered");
+ tester_print("Adding advertising instance while powered");
cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp, 1);
mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -4926,22 +5209,13 @@ static void setup_add_advertising_connectable(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };
- tester_print("Adding advertising instance while unpowered");
+ tester_print("Adding advertising instance while connectable");
cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp, 1);
mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -4965,23 +5239,42 @@ static void setup_add_advertising_timeout(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };
- tester_print("Adding advertising instance while unpowered");
+ tester_print("Adding advertising instance with timeout");
cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
+ setup_add_adv_param(cp, 1);
+ cp->timeout = 1;
- cp->instance = 1;
- cp->timeout = 5;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+}
+
+static void setup_add_advertising_duration(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding instance with long timeout/short duration");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+ cp->duration = 1;
+ cp->timeout = 30;
mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -4997,26 +5290,61 @@ static void setup_add_advertising_timeout(const void *test_data)
NULL, NULL);
}
+static void setup_power_cycle_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ unsigned char param_off[] = { 0x00 };
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param_off), &param_off,
+ NULL, NULL, NULL);
+
+ setup_bthost();
+}
+
+static void setup_add_advertising_power_cycle(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param_on[] = { 0x01 };
+
+ tester_print("Adding instance without timeout and power cycle");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param_on), &param_on,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param_on), &param_on,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_power_cycle_callback,
+ NULL, NULL);
+}
+
static void setup_set_and_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };
- tester_print("Adding advertising instance while unpowered");
+ tester_print("Set and add advertising instance");
cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp, 1);
mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5036,6 +5364,61 @@ static void setup_set_and_add_advertising(const void *test_data)
NULL, NULL);
}
+static void setup_multi_adv_second_instance(uint8_t status, uint16_t length,
+ const void *param, void *user_data) {
+ struct mgmt_rp_add_advertising *rp =
+ (struct mgmt_rp_add_advertising *) param;
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Add Advertising setup complete (instance %d)",
+ rp->instance);
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 2);
+ cp->timeout = 1;
+ cp->duration = 1;
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+}
+
+static void setup_multi_adv(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding two instances with timeout 1 and duration 1");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+ cp->timeout = 1;
+ cp->duration = 1;
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_multi_adv_second_instance,
+ NULL, NULL);
+}
+
static void setup_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -5196,6 +5579,9 @@ proceed:
for (cmd = test->setup_settings; *cmd; cmd++) {
unsigned char simple_param[] = { 0x01 };
unsigned char discov_param[] = { 0x01, 0x00, 0x00 };
+ unsigned char privacy_param[] = { 0x01,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
unsigned char *param = simple_param;
size_t param_size = sizeof(simple_param);
mgmt_request_func_t func = NULL;
@@ -5214,6 +5600,11 @@ proceed:
param = discov_param;
}
+ if (*cmd == MGMT_OP_SET_PRIVACY) {
+ param_size = sizeof(privacy_param);
+ param = privacy_param;
+ }
+
if (*cmd == MGMT_OP_SET_LE && test->setup_nobredr) {
unsigned char off[] = { 0x00 };
mgmt_send(data->mgmt, *cmd, data->mgmt_index,
@@ -5332,8 +5723,8 @@ static void command_generic_callback(uint8_t status, uint16_t length,
const void *expect_param = test->expect_param;
uint16_t expect_len = test->expect_len;
- tester_print("Command 0x%04x finished with status 0x%02x",
- test->send_opcode, status);
+ tester_print("%s (0x%04x): %s (0x%02x)", mgmt_opstr(test->send_opcode),
+ test->send_opcode, mgmt_errstr(status), status);
if (status != test->expect_status) {
tester_test_failed();
@@ -5345,12 +5736,14 @@ static void command_generic_callback(uint8_t status, uint16_t length,
expect_param = test->expect_func(&expect_len);
if (length != expect_len) {
+ tester_warn("Invalid cmd response parameter size");
tester_test_failed();
return;
}
if (expect_param && expect_len > 0 &&
memcmp(param, expect_param, length)) {
+ tester_warn("Unexpected cmd response parameter value");
tester_test_failed();
return;
}
@@ -5448,7 +5841,13 @@ static void test_command_generic(const void *test_data)
test_add_condition(data);
}
- tester_print("Sending command 0x%04x", test->send_opcode);
+ if (test->send_opcode == 0x0000) {
+ tester_print("Executing no-op test");
+ return;
+ }
+
+ tester_print("Sending %s (0x%04x)", mgmt_opstr(test->send_opcode),
+ test->send_opcode);
if (test->send_func)
send_param = test->send_func(&send_len);
@@ -5467,6 +5866,57 @@ static void test_command_generic(const void *test_data)
test_add_condition(data);
}
+static void check_scan(void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ if (hciemu_get_master_le_scan_enable(data->hciemu)) {
+ tester_warn("LE scan still enabled");
+ tester_test_failed();
+ return;
+ }
+
+ if (hciemu_get_master_scan_enable(data->hciemu)) {
+ tester_warn("BR/EDR scan still enabled");
+ tester_test_failed();
+ return;
+ }
+
+ test_condition_complete(data);
+}
+
+static void test_remove_device(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ test_command_generic(test_data);
+ tester_wait(1, check_scan, NULL);
+ test_add_condition(data);
+}
+
+static void test_device_found(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+ struct bthost *bthost;
+
+ bthost = hciemu_client_get_host(data->hciemu);
+
+ if ((data->hciemu_type == HCIEMU_TYPE_LE) ||
+ (data->hciemu_type == HCIEMU_TYPE_BREDRLE)) {
+ if (test->set_adv)
+ bthost_set_adv_data(bthost, test->adv_data,
+ test->adv_data_len);
+
+ bthost_set_adv_enable(bthost, 0x01);
+ }
+
+ if (data->hciemu_type != HCIEMU_TYPE_LE)
+ bthost_write_scan_enable(bthost, 0x03);
+
+ test_command_generic(test_data);
+}
+
static void pairing_new_conn(uint16_t handle, void *user_data)
{
struct test_data *data = tester_get_data();
@@ -5525,7 +5975,8 @@ static void connected_event(uint16_t index, uint16_t length, const void *param,
const void *send_param = test->send_param;
uint16_t send_len = test->send_len;
- tester_print("Sending command 0x%04x", test->send_opcode);
+ tester_print("Sending %s 0x%04x", mgmt_opstr(test->send_opcode),
+ test->send_opcode);
if (test->send_func)
send_param = test->send_func(&send_len);
@@ -5653,6 +6104,9 @@ int main(int argc, char *argv[])
test_bredrle("Set powered on - Invalid index",
&set_powered_on_invalid_index_test,
NULL, test_command_generic);
+ test_le("Set powered on - Privacy and Advertising",
+ &set_powered_on_privacy_adv_test,
+ NULL, test_command_generic);
test_bredrle("Set powered off - Success",
&set_powered_off_success_test,
@@ -6340,6 +6794,9 @@ int main(int argc, char *argv[])
test_bredrle("Add Device - Invalid Params 3",
&add_device_fail_3,
NULL, test_command_generic);
+ test_bredrle("Add Device - Invalid Params 4",
+ &add_device_fail_4,
+ NULL, test_command_generic);
test_bredrle("Add Device - Success 1",
&add_device_success_1,
NULL, test_command_generic);
@@ -6362,6 +6819,9 @@ int main(int argc, char *argv[])
test_bredrle("Remove Device - Invalid Params 2",
&remove_device_fail_2,
NULL, test_command_generic);
+ test_bredrle("Remove Device - Invalid Params 3",
+ &remove_device_fail_3,
+ NULL, test_command_generic);
test_bredrle("Remove Device - Success 1",
&remove_device_success_1,
setup_add_device, test_command_generic);
@@ -6370,13 +6830,13 @@ int main(int argc, char *argv[])
setup_add_device, test_command_generic);
test_bredrle("Remove Device - Success 3",
&remove_device_success_3,
- setup_add_device, test_command_generic);
+ setup_add_device, test_remove_device);
test_le("Remove Device - Success 4",
&remove_device_success_4,
- setup_add_device, test_command_generic);
+ setup_add_device, test_remove_device);
test_le("Remove Device - Success 5",
&remove_device_success_5,
- setup_add_device, test_command_generic);
+ setup_add_device, test_remove_device);
test_bredrle("Read Advertising Features - Invalid parameters",
&read_adv_features_invalid_param_test,
@@ -6384,6 +6844,13 @@ int main(int argc, char *argv[])
test_bredrle("Read Advertising Features - Invalid index",
&read_adv_features_invalid_index_test,
NULL, test_command_generic);
+ test_bredrle("Read Advertising Features - Success 1 (No instance)",
+ &read_adv_features_success_1,
+ NULL, test_command_generic);
+ test_bredrle("Read Advertising Features - Success 2 (One instance)",
+ &read_adv_features_success_2,
+ setup_add_advertising,
+ test_command_generic);
test_bredrle("Add Advertising - Failure: LE off",
&add_advertising_fail_1,
@@ -6418,70 +6885,97 @@ int main(int argc, char *argv[])
test_le("Add Advertising - Invalid Params 10 (ScRsp too long)",
&add_advertising_fail_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Not Powered",
+ test_bredrle("Add Advertising - Rejected (Timeout, !Powered)",
&add_advertising_fail_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Power off",
- &add_advertising_timeout_power_off,
- setup_add_advertising_timeout,
- test_command_generic);
- test_bredrle("Add Advertising - Success 1",
+ test_bredrle("Add Advertising - Success 1 (Powered, Add Adv Inst)",
&add_advertising_success_1,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 2",
- &add_advertising_success_2,
+ test_bredrle("Add Advertising - Success 2 (!Powered, Add Adv Inst)",
+ &add_advertising_success_pwron_data,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Success 3",
- &add_advertising_success_3,
+ test_bredrle("Add Advertising - Success 3 (!Powered, Adv Enable)",
+ &add_advertising_success_pwron_enabled,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising on override 1",
+ test_bredrle("Add Advertising - Success 4 (Set Adv on override)",
&add_advertising_success_4,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising off override 2",
+ test_bredrle("Add Advertising - Success 5 (Set Adv off override)",
&add_advertising_success_5,
setup_set_and_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 4",
+ test_bredrle("Add Advertising - Success 6 (Scan Rsp Dta, Adv ok)",
&add_advertising_success_6,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 5",
+ test_bredrle("Add Advertising - Success 7 (Scan Rsp Dta, Scan ok) ",
&add_advertising_success_7,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 6 - Flag 0",
+ test_bredrle("Add Advertising - Success 8 (Connectable Flag)",
&add_advertising_success_8,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 7 - Flag 1",
+ test_bredrle("Add Advertising - Success 9 (General Discov Flag)",
&add_advertising_success_9,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 2",
+ test_bredrle("Add Advertising - Success 10 (Limited Discov Flag)",
&add_advertising_success_10,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 3",
+ test_bredrle("Add Advertising - Success 11 (Managed Flags)",
&add_advertising_success_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 9 - Flag 4",
+ test_bredrle("Add Advertising - Success 12 (TX Power Flag)",
&add_advertising_success_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 10 - ADV_SCAN_IND",
+ test_bredrle("Add Advertising - Success 13 (ADV_SCAN_IND)",
&add_advertising_success_13,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 11 - ADV_NONCONN_IND",
+ test_bredrle("Add Advertising - Success 14 (ADV_NONCONN_IND)",
&add_advertising_success_14,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 12 - ADV_IND",
+ test_bredrle("Add Advertising - Success 15 (ADV_IND)",
&add_advertising_success_15,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 13 - connectable -> on",
+ test_bredrle("Add Advertising - Success 16 (Connectable -> on)",
&add_advertising_success_16,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 14 - connectable -> off",
+ test_bredrle("Add Advertising - Success 17 (Connectable -> off)",
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
+ /* Adv instances with a timeout do NOT survive a power cycle. */
+ test_bredrle("Add Advertising - Success 18 (Power -> off, Remove)",
+ &add_advertising_power_off,
+ setup_add_advertising_timeout,
+ test_command_generic);
+ /* Adv instances without timeout survive a power cycle. */
+ test_bredrle("Add Advertising - Success 19 (Power -> off, Keep)",
+ &add_advertising_success_pwron_data,
+ setup_add_advertising_power_cycle,
+ test_command_generic);
+ /* Changing an advertising instance while it is still being
+ * advertised will immediately update the advertised data if
+ * there is no other instance to switch to.
+ */
+ test_bredrle("Add Advertising - Success 20 (Add Adv override)",
+ &add_advertising_success_18,
+ setup_add_advertising,
+ test_command_generic);
+ /* An instance should be removed when its timeout has been reached.
+ * Advertising will also be disabled if this was the last instance.
+ */
+ test_bredrle_full("Add Advertising - Success 21 (Timeout expires)",
+ &add_advertising_timeout_expired,
+ setup_add_advertising_timeout,
+ test_command_generic, 3);
+ /* LE off will clear (remove) all instances. */
+ test_bredrle("Add Advertising - Success 22 (LE -> off, Remove)",
+ &add_advertising_le_off,
+ setup_add_advertising,
+ test_command_generic);
+
test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
@@ -6495,6 +6989,22 @@ int main(int argc, char *argv[])
setup_add_advertising,
test_command_generic);
+ /* When advertising two instances, the instances should be
+ * advertised in a round-robin fashion.
+ */
+ test_bredrle("Multi Advertising - Success 1 (Instance Switch)",
+ &multi_advertising_switch,
+ setup_multi_adv,
+ test_command_generic);
+ /* Adding a new instance when one is already being advertised
+ * will switch to the new instance after the first has reached
+ * its duration. A long timeout has been set to
+ */
+ test_bredrle_full("Multi Advertising - Success 2 (Add Second Inst)",
+ &multi_advertising_add_second,
+ setup_add_advertising_duration,
+ test_command_generic, 3);
+
test_bredrle("Read Local OOB Data - Not powered",
&read_local_oob_not_powered_test,
NULL, test_command_generic);
@@ -6514,5 +7024,12 @@ int main(int argc, char *argv[])
&read_local_oob_success_sc_test,
NULL, test_command_generic);
+ test_bredrle("Device Found - Advertising data - Zero padded",
+ &device_found_gtag,
+ NULL, test_device_found);
+ test_bredrle("Device Found - Advertising data - Invalid field",
+ &device_found_invalid_field,
+ NULL, test_device_found);
+
return tester_run();
}
diff --git a/tools/mpris-proxy.c b/tools/mpris-proxy.c
index 693055ed..bf8148fe 100644
--- a/tools/mpris-proxy.c
+++ b/tools/mpris-proxy.c
@@ -406,7 +406,7 @@ static DBusHandlerResult player_message(DBusConnection *conn,
done:
dbus_message_unref(copy);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return DBUS_HANDLER_RESULT_HANDLED;
}
static struct player *find_player_by_bus_name(const char *name)
diff --git a/tools/nokfw.c b/tools/nokfw.c
new file mode 100644
index 00000000..20ff846b
--- /dev/null
+++ b/tools/nokfw.c
@@ -0,0 +1,247 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012-2013 Intel Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+struct neg_cmd {
+ uint8_t ack;
+ uint16_t baud;
+ uint16_t unused1;
+ uint8_t proto;
+ uint16_t sys_clk;
+ uint16_t unused2;
+} __attribute__ ((packed));
+
+struct alive_pkt {
+ uint8_t mid;
+ uint8_t unused;
+} __attribute__ ((packed));
+
+static void print_cmd(uint16_t opcode, const uint8_t *buf, uint8_t plen)
+{
+ switch (opcode) {
+ case 0x0c43:
+ printf(" Write_Inquiry_Scan_Type [type=%u]", buf[0]);
+ break;
+ case 0x0c47:
+ printf(" Write_Page_Scan_Type [type=%u]", buf[0]);
+ break;
+ case 0xfc01:
+ printf(" Write_BD_ADDR [bdaddr=%02x:%02x:%02x:%02x:%02x:%02x]",
+ buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
+ break;
+ case 0xfc0b:
+ printf(" Write_Local_Supported_Features");
+ printf(" [features=%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+ break;
+ case 0xfc0a:
+ printf(" Super_Peek_Poke [type=%u]", buf[0]);
+ break;
+ case 0xfc15:
+ printf(" FM_RDS_Command [register=0x%02x,mode=%u]",
+ buf[0], buf[1]);
+ break;
+ case 0xfc18:
+ printf(" Update_UART_Baud_Rate");
+ break;
+ case 0xfc1c:
+ printf(" Write_SCO_PCM_Int_Param");
+ break;
+ case 0xfc1e:
+ printf(" Write_PCM_Data_Format_Param");
+ break;
+ case 0xfc22:
+ printf(" Write_SCO_Time_Slot [slot=%u]", buf[0]);
+ break;
+ case 0xfc41:
+ printf(" Write_Collaboration_Mode");
+ break;
+ case 0xfc4c:
+ printf(" Write_RAM [address=0x%08x]",
+ buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
+ break;
+ case 0xfc4e:
+ printf(" Launch_RAM [address=0x%08x]",
+ buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
+ break;
+ case 0xfc61:
+ printf(" Write_PCM_Pins");
+ break;
+ }
+}
+
+static void analyze_memory(const uint8_t *buf, size_t len)
+{
+ const uint8_t *ptr = buf;
+ const struct neg_cmd *neg;
+ const struct alive_pkt *alive;
+ uint16_t pkt_len, opcode;
+ uint8_t pkt_type, plen;
+
+ while (ptr < buf + len) {
+ pkt_len = ptr[0] | ptr[1] << 8;
+ pkt_type = ptr[2];
+
+ printf("len=%-3u type=%u,", pkt_len, pkt_type);
+
+ switch (pkt_type) {
+ case 0x01:
+ opcode = ptr[3] | ptr[4] << 8;
+ plen = ptr[5];
+ printf("%-5s opcode=0x%04x plen=%-3u", "cmd",
+ opcode, plen);
+ print_cmd(opcode, ptr + 6, plen);
+ break;
+ case 0x06:
+ plen = ptr[3];
+ printf("%-5s plen=%-2u", "neg", plen);
+ neg = (void *) (ptr + 4);
+ printf(" [ack=%u baud=%u proto=0x%02x sys_clk=%u]",
+ neg->ack, neg->baud, neg->proto, neg->sys_clk);
+ break;
+ case 0x07:
+ plen = ptr[3];
+ printf("%-5s plen=%-2u", "alive", plen);
+ alive = (void *) (ptr + 4);
+ printf(" [mid=0x%02x]", alive->mid);
+ break;
+ case 0x08:
+ opcode = ptr[3] | ptr[4] << 8;
+ plen = ptr[5];
+ printf("%-5s opcode=0x%04x plen=%-3u", "radio",
+ opcode, plen);
+ print_cmd(opcode, ptr + 6, plen);
+ break;
+ default:
+ printf("unknown");
+ break;
+ }
+
+ printf("\n");
+
+ ptr += pkt_len + 2;
+ }
+}
+
+static void analyze_file(const char *pathname)
+{
+ struct stat st;
+ void *map;
+ int fd;
+
+ printf("Analyzing %s\n", pathname);
+
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ perror("Failed to open file");
+ return;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "Failed get file size\n");
+ close(fd);
+ return;
+ }
+
+ if (st.st_size == 0) {
+ fprintf(stderr, "Empty file\n");
+ close(fd);
+ return;
+ }
+
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ fprintf(stderr, "Failed to map file\n");
+ close(fd);
+ return;
+ }
+
+ analyze_memory(map, st.st_size);
+
+ munmap(map, st.st_size);
+ close(fd);
+}
+
+static void usage(void)
+{
+ printf("Nokia Bluetooth firmware analyzer\n"
+ "Usage:\n");
+ printf("\tnokfw [options] <file>\n");
+ printf("Options:\n"
+ "\t-h, --help Show help options\n");
+}
+
+static const struct option main_options[] = {
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "vh", main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'v':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (argc - optind < 1) {
+ fprintf(stderr, "No input firmware files provided\n");
+ return EXIT_FAILURE;
+ }
+
+ for (i = optind; i < argc; i++)
+ analyze_file(argv[i]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/obex-client-tool.c b/tools/obex-client-tool.c
index 4f931f6d..d0ba8a65 100644
--- a/tools/obex-client-tool.c
+++ b/tools/obex-client-tool.c
@@ -432,6 +432,7 @@ int main(int argc, char *argv[])
if (err != NULL) {
g_printerr("%s\n", err->message);
g_error_free(err);
+ g_option_context_free(context);
exit(EXIT_FAILURE);
}
@@ -445,8 +446,10 @@ int main(int argc, char *argv[])
else
io = unix_connect(transport);
- if (io == NULL)
+ if (io == NULL) {
+ g_option_context_free(context);
exit(EXIT_FAILURE);
+ }
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_term;
diff --git a/tools/obexctl.c b/tools/obexctl.c
index 4faff6b6..86c81d57 100644
--- a/tools/obexctl.c
+++ b/tools/obexctl.c
@@ -758,7 +758,7 @@ static void send_reply(DBusMessage *message, void *user_data)
dbus_error_init(&error);
if (dbus_set_error_from_message(&error, message) == TRUE) {
- rl_printf("Failed to send: %s\n", error.name);
+ rl_printf("Failed to send/pull: %s\n", error.name);
dbus_error_free(&error);
return;
}
@@ -792,6 +792,23 @@ static void opp_send(GDBusProxy *proxy, int argc, char *argv[])
g_dbus_proxy_get_path(proxy));
}
+static void opp_pull(GDBusProxy *proxy, int argc, char *argv[])
+{
+ if (argc < 2) {
+ rl_printf("Missing file argument\n");
+ return;
+ }
+
+ if (g_dbus_proxy_method_call(proxy, "PullBusinessCard", send_setup,
+ send_reply, g_strdup(argv[1]), g_free) == FALSE) {
+ rl_printf("Failed to pull\n");
+ return;
+ }
+
+ rl_printf("Attempting to pull %s from %s\n", argv[1],
+ g_dbus_proxy_get_path(proxy));
+}
+
static void push_reply(DBusMessage *message, void *user_data)
{
DBusMessageIter iter;
@@ -869,6 +886,22 @@ static void cmd_send(int argc, char *argv[])
rl_printf("Command not supported\n");
}
+static void cmd_pull(int argc, char *argv[])
+{
+ GDBusProxy *proxy;
+
+ if (!check_default_session())
+ return;
+
+ proxy = find_opp(g_dbus_proxy_get_path(default_session));
+ if (proxy) {
+ opp_pull(proxy, argc, argv);
+ return;
+ }
+
+ rl_printf("Command not supported\n");
+}
+
static void change_folder_reply(DBusMessage *message, void *user_data)
{
DBusError error;
@@ -1979,6 +2012,8 @@ static const struct {
{ "suspend", "<transfer>", cmd_suspend, "Suspend transfer" },
{ "resume", "<transfer>", cmd_resume, "Resume transfer" },
{ "send", "<file>", cmd_send, "Send file" },
+ { "pull", "<file>", cmd_pull,
+ "Pull Vobject & stores in file" },
{ "cd", "<path>", cmd_cd, "Change current folder" },
{ "ls", "<options>", cmd_ls, "List current folder" },
{ "cp", "<source file> <destination file>", cmd_cp,
diff --git a/tools/parse_companies.pl b/tools/parse_companies.pl
new file mode 100644
index 00000000..6dc358ee
--- /dev/null
+++ b/tools/parse_companies.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+# parse companies from
+# https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+
+use strict;
+# use URI::Encode qw(uri_decode);
+
+my %known_entities = (
+ 'nbsp' => ' ',
+ 'eacute' => 'é',
+ 'auml' => 'ä',
+);
+
+# better to use URI::Encode if you have it
+sub uri_decode {
+ my $name = $_[0];
+ foreach my $entity (keys %known_entities) {
+ my $to = $known_entities{$entity};
+ $name =~ s/&$entity;/$to/g;
+ }
+ foreach my $entity (map { lc $_ } $name =~ /&([^;]+);/g) {
+ if ($entity ne 'amp') {
+ print "Unable to convert &$entity;, giving up\n";
+ exit 1;
+ }
+ }
+ $name =~ s/&amp;/&/ig;
+ $name =~ s/&nbsp;/ /ig;
+ return $name;
+}
+
+# never parse HTML with regex!
+# except when you should
+
+my $identifier;
+my $next_is_name = 0;
+
+while (<>) {
+ s/\xe2\x80\x8b//g; # kill zero width space
+
+ # grab identifier (in hex)
+ if (/\<td.*(0x[0-9A-F]{4})/i) {
+ $identifier = $1;
+ $next_is_name = 1;
+
+ # next <td> should be company name
+ } elsif ($next_is_name && m|\<td.*\>(.*)\</td\>|) {
+ my $name = uri_decode($1);
+ $name =~ s/^\s+//g; # kill leading
+ $name =~ s/\s+$//g; # and trailing space
+ my $id = hex($identifier);
+ if ($id != 65535) {
+ print "\tcase $id:\n";
+ print "\t\treturn \"$name\";\n";
+ }
+ $next_is_name = 0;
+ }
+}
diff --git a/tools/parser/att.c b/tools/parser/att.c
index 5d9bea41..82766c77 100644
--- a/tools/parser/att.c
+++ b/tools/parser/att.c
@@ -256,9 +256,9 @@ static const char *uuid2str(uint16_t uuid)
static void att_error_dump(int level, struct frame *frm)
{
- uint8_t op = get_u8(frm);
- uint16_t handle = btohs(htons(get_u16(frm)));
- uint8_t err = get_u8(frm);
+ uint8_t op = p_get_u8(frm);
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
+ uint8_t err = p_get_u8(frm);
p_indent(level, frm);
printf("Error: %s (%d)\n", atterror2str(err), err);
@@ -269,7 +269,7 @@ static void att_error_dump(int level, struct frame *frm)
static void att_mtu_req_dump(int level, struct frame *frm)
{
- uint16_t client_rx_mtu = btohs(htons(get_u16(frm)));
+ uint16_t client_rx_mtu = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("client rx mtu %d\n", client_rx_mtu);
@@ -277,7 +277,7 @@ static void att_mtu_req_dump(int level, struct frame *frm)
static void att_mtu_resp_dump(int level, struct frame *frm)
{
- uint16_t server_rx_mtu = btohs(htons(get_u16(frm)));
+ uint16_t server_rx_mtu = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("server rx mtu %d\n", server_rx_mtu);
@@ -285,8 +285,8 @@ static void att_mtu_resp_dump(int level, struct frame *frm)
static void att_find_info_req_dump(int level, struct frame *frm)
{
- uint16_t start = btohs(htons(get_u16(frm)));
- uint16_t end = btohs(htons(get_u16(frm)));
+ uint16_t start = btohs(htons(p_get_u16(frm)));
+ uint16_t end = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("start 0x%4.4x, end 0x%4.4x\n", start, end);
@@ -298,7 +298,7 @@ static void print_uuid128(struct frame *frm)
int i;
for (i = 0; i < 16; i++)
- uuid[15 - i] = get_u8(frm);
+ uuid[15 - i] = p_get_u8(frm);
for (i = 0; i < 16; i++) {
printf("%02x", uuid[i]);
@@ -309,7 +309,7 @@ static void print_uuid128(struct frame *frm)
static void att_find_info_resp_dump(int level, struct frame *frm)
{
- uint8_t fmt = get_u8(frm);
+ uint8_t fmt = p_get_u8(frm);
p_indent(level, frm);
@@ -317,8 +317,8 @@ static void att_find_info_resp_dump(int level, struct frame *frm)
printf("format: uuid-16\n");
while (frm->len > 0) {
- uint16_t handle = btohs(htons(get_u16(frm)));
- uint16_t uuid = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
+ uint16_t uuid = btohs(htons(p_get_u16(frm)));
p_indent(level + 1, frm);
printf("handle 0x%4.4x, uuid 0x%4.4x (%s)\n", handle, uuid,
uuid2str(uuid));
@@ -327,7 +327,7 @@ static void att_find_info_resp_dump(int level, struct frame *frm)
printf("format: uuid-128\n");
while (frm->len > 0) {
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level + 1, frm);
printf("handle 0x%4.4x, uuid ", handle);
@@ -339,9 +339,9 @@ static void att_find_info_resp_dump(int level, struct frame *frm)
static void att_find_by_type_req_dump(int level, struct frame *frm)
{
- uint16_t start = btohs(htons(get_u16(frm)));
- uint16_t end = btohs(htons(get_u16(frm)));
- uint16_t uuid = btohs(htons(get_u16(frm)));
+ uint16_t start = btohs(htons(p_get_u16(frm)));
+ uint16_t end = btohs(htons(p_get_u16(frm)));
+ uint16_t uuid = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("start 0x%4.4x, end 0x%4.4x, uuid 0x%4.4x\n", start, end, uuid);
@@ -349,15 +349,15 @@ static void att_find_by_type_req_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("value");
while (frm->len > 0)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
}
static void att_find_by_type_resp_dump(int level, struct frame *frm)
{
while (frm->len > 0) {
- uint16_t uuid = btohs(htons(get_u16(frm)));
- uint16_t end = btohs(htons(get_u16(frm)));
+ uint16_t uuid = btohs(htons(p_get_u16(frm)));
+ uint16_t end = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("Found attr 0x%4.4x, group end handle 0x%4.4x\n",
@@ -367,15 +367,15 @@ static void att_find_by_type_resp_dump(int level, struct frame *frm)
static void att_read_by_type_req_dump(int level, struct frame *frm)
{
- uint16_t start = btohs(htons(get_u16(frm)));
- uint16_t end = btohs(htons(get_u16(frm)));
+ uint16_t start = btohs(htons(p_get_u16(frm)));
+ uint16_t end = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("start 0x%4.4x, end 0x%4.4x\n", start, end);
p_indent(level, frm);
if (frm->len == 2) {
- printf("type-uuid 0x%4.4x\n", btohs(htons(get_u16(frm))));
+ printf("type-uuid 0x%4.4x\n", btohs(htons(p_get_u16(frm))));
} else if (frm->len == 16) {
printf("type-uuid ");
print_uuid128(frm);
@@ -389,20 +389,20 @@ static void att_read_by_type_req_dump(int level, struct frame *frm)
static void att_read_by_type_resp_dump(int level, struct frame *frm)
{
- uint8_t length = get_u8(frm);
+ uint8_t length = p_get_u8(frm);
p_indent(level, frm);
printf("length: %d\n", length);
while (frm->len > 0) {
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
int val_len = length - 2;
int i;
p_indent(level + 1, frm);
printf("handle 0x%4.4x, value ", handle);
for (i = 0; i < val_len; i++) {
- printf("0x%.2x ", get_u8(frm));
+ printf("0x%.2x ", p_get_u8(frm));
}
printf("\n");
}
@@ -410,7 +410,7 @@ static void att_read_by_type_resp_dump(int level, struct frame *frm)
static void att_read_req_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle 0x%4.4x\n", handle);
@@ -418,8 +418,8 @@ static void att_read_req_dump(int level, struct frame *frm)
static void att_read_blob_req_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
- uint16_t offset = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
+ uint16_t offset = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle 0x%4.4x offset 0x%4.4x\n", handle, offset);
@@ -431,7 +431,7 @@ static void att_read_blob_resp_dump(int level, struct frame *frm)
printf("value");
while (frm->len > 0)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
}
@@ -442,7 +442,7 @@ static void att_read_multi_req_dump(int level, struct frame *frm)
while (frm->len > 0) {
p_indent(level, frm);
- printf("handle 0x%4.4x\n", btohs(htons(get_u16(frm))));
+ printf("handle 0x%4.4x\n", btohs(htons(p_get_u16(frm))));
}
}
@@ -452,17 +452,17 @@ static void att_read_multi_resp_dump(int level, struct frame *frm)
printf("values");
while (frm->len > 0)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
}
static void att_read_by_group_resp_dump(int level, struct frame *frm)
{
- uint8_t length = get_u8(frm);
+ uint8_t length = p_get_u8(frm);
while (frm->len > 0) {
- uint16_t attr_handle = btohs(htons(get_u16(frm)));
- uint16_t end_grp_handle = btohs(htons(get_u16(frm)));
+ uint16_t attr_handle = btohs(htons(p_get_u16(frm)));
+ uint16_t end_grp_handle = btohs(htons(p_get_u16(frm)));
uint8_t remaining = length - 4;
p_indent(level, frm);
@@ -472,7 +472,7 @@ static void att_read_by_group_resp_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("value");
while (remaining > 0) {
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
remaining--;
}
printf("\n");
@@ -481,39 +481,39 @@ static void att_read_by_group_resp_dump(int level, struct frame *frm)
static void att_write_req_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle 0x%4.4x value ", handle);
while (frm->len > 0)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
}
static void att_signed_write_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
int value_len = frm->len - 12; /* handle:2 already accounted, sig: 12 */
p_indent(level, frm);
printf("handle 0x%4.4x value ", handle);
while (value_len--)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
p_indent(level, frm);
printf("auth signature ");
while (frm->len > 0)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
}
static void att_prep_write_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
- uint16_t val_offset = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
+ uint16_t val_offset = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("attr handle 0x%4.4x, value offset 0x%4.4x\n", handle,
@@ -522,13 +522,13 @@ static void att_prep_write_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("part attr value ");
while (frm->len > 0)
- printf(" 0x%2.2x", get_u8(frm));
+ printf(" 0x%2.2x", p_get_u8(frm));
printf("\n");
}
static void att_exec_write_req_dump(int level, struct frame *frm)
{
- uint8_t flags = get_u8(frm);
+ uint8_t flags = p_get_u8(frm);
p_indent(level, frm);
if (flags == 0x00)
@@ -541,7 +541,7 @@ static void att_exec_write_req_dump(int level, struct frame *frm)
static void att_handle_notify_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle 0x%4.4x\n", handle);
@@ -549,7 +549,7 @@ static void att_handle_notify_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("value ");
while (frm->len > 0)
- printf("0x%.2x ", get_u8(frm));
+ printf("0x%.2x ", p_get_u8(frm));
printf("\n");
}
@@ -557,7 +557,7 @@ void att_dump(int level, struct frame *frm)
{
uint8_t op;
- op = get_u8(frm);
+ op = p_get_u8(frm);
p_indent(level, frm);
printf("ATT: %s (0x%.2x)\n", attop2str(op), op);
diff --git a/tools/parser/avctp.c b/tools/parser/avctp.c
index 58b181dc..70c5f668 100644
--- a/tools/parser/avctp.c
+++ b/tools/parser/avctp.c
@@ -57,8 +57,8 @@ void avctp_dump(int level, struct frame *frm, uint16_t psm)
p_indent(level, frm);
- hdr = get_u8(frm);
- pid = get_u16(frm);
+ hdr = p_get_u8(frm);
+ pid = p_get_u16(frm);
printf("AVCTP %s: %s %s: pt 0x%02x transaction %d pid 0x%04x\n",
psm == 23 ? "Control" : "Browsing",
diff --git a/tools/parser/avdtp.c b/tools/parser/avdtp.c
index 5969067c..4f535530 100644
--- a/tools/parser/avdtp.c
+++ b/tools/parser/avdtp.c
@@ -154,6 +154,8 @@ static char *vndcodec2str(uint32_t vendor, uint16_t vndcodec)
{
if (vendor == 0x0000004f && vndcodec == 0x0001)
return "aptX";
+ else if (vendor == 0x0000012d && vndcodec == 0x00aa)
+ return "LDAC";
return "Unknown";
}
@@ -186,7 +188,7 @@ static void errorcode(int level, struct frame *frm)
uint8_t code;
p_indent(level, frm);
- code = get_u8(frm);
+ code = p_get_u8(frm);
printf("Error code %d\n", code);
}
@@ -195,7 +197,7 @@ static void acp_seid(int level, struct frame *frm)
uint8_t seid;
p_indent(level, frm);
- seid = get_u8(frm);
+ seid = p_get_u8(frm);
printf("ACP SEID %d\n", seid >> 2);
}
@@ -204,8 +206,8 @@ static void acp_int_seid(int level, struct frame *frm)
uint8_t acp_seid, int_seid;
p_indent(level, frm);
- acp_seid = get_u8(frm);
- int_seid = get_u8(frm);
+ acp_seid = p_get_u8(frm);
+ int_seid = p_get_u8(frm);
printf("ACP SEID %d - INT SEID %d\n", acp_seid >> 2, int_seid >> 2);
}
@@ -215,8 +217,8 @@ static void capabilities(int level, struct frame *frm)
while (frm->len > 1) {
p_indent(level, frm);
- cat = get_u8(frm);
- len = get_u8(frm);
+ cat = p_get_u8(frm);
+ len = p_get_u8(frm);
if (cat == 7) {
uint8_t type, codec;
@@ -224,12 +226,12 @@ static void capabilities(int level, struct frame *frm)
uint32_t bitrate, vendor = 0;
int i;
- type = get_u8(frm);
- codec = get_u8(frm);
+ type = p_get_u8(frm);
+ codec = p_get_u8(frm);
if (codec == 255) {
- vendor = btohl(htonl(get_u32(frm)));
- vndcodec = btohs(htons(get_u16(frm)));
+ vendor = btohl(htonl(p_get_u32(frm)));
+ vndcodec = btohs(htons(p_get_u16(frm)));
printf("%s - %s (%s)\n", cat2str(cat),
codec2str(type, codec),
@@ -241,7 +243,7 @@ static void capabilities(int level, struct frame *frm)
switch (codec) {
case 0:
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
if (tmp & 0x80)
printf("16kHz ");
@@ -262,7 +264,7 @@ static void capabilities(int level, struct frame *frm)
if (tmp & 0x01)
printf("JointStereo ");
printf("\n");
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
if (tmp & 0x80)
printf("4 ");
@@ -285,12 +287,12 @@ static void capabilities(int level, struct frame *frm)
if (tmp & 0x01)
printf("Loudness ");
printf("\n");
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
- printf("Bitpool Range %d-%d\n", tmp, get_u8(frm));
+ printf("Bitpool Range %d-%d\n", tmp, p_get_u8(frm));
break;
case 1:
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
printf("Layers: ");
if (tmp & 0x80)
@@ -313,7 +315,7 @@ static void capabilities(int level, struct frame *frm)
if (tmp & 0x01)
printf("JointStereo ");
printf("\n");
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
printf("Media Payload Format: RFC-2250 %s\n",
tmp & 0x40 ? "RFC-3119" : "");
@@ -331,7 +333,7 @@ static void capabilities(int level, struct frame *frm)
if (tmp & 0x01)
printf("48kHz ");
printf("\n");
- tmp = get_u16(frm);
+ tmp = p_get_u16(frm);
p_indent(level + 1, frm);
printf("VBR: %s\n",
tmp & 0x8000 ? "Yes" : "No");
@@ -347,7 +349,7 @@ static void capabilities(int level, struct frame *frm)
printf("\n");
break;
case 2:
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
if (tmp & 0x80)
printf("MPEG-2 AAC LC ");
@@ -358,7 +360,7 @@ static void capabilities(int level, struct frame *frm)
if (tmp & 0x10)
printf("MPEG-4 AAC scalable ");
printf("\n");
- tmp = get_u16(frm);
+ tmp = p_get_u16(frm);
freq = tmp >> 4;
p_indent(level + 1, frm);
if (freq & 0x0800)
@@ -393,8 +395,8 @@ static void capabilities(int level, struct frame *frm)
if (tmp & 0x01)
printf("2 ");
printf("Channels\n");
- tmp = get_u8(frm);
- bitrate = ((tmp & 0x7f) << 16) | get_u16(frm);
+ tmp = p_get_u8(frm);
+ bitrate = ((tmp & 0x7f) << 16) | p_get_u16(frm);
p_indent(level + 1, frm);
printf("%ubps ", bitrate);
printf("%s\n", tmp & 0x80 ? "VBR" : "");
@@ -402,7 +404,7 @@ static void capabilities(int level, struct frame *frm)
case 255:
if (vendor == 0x0000004f &&
vndcodec == 0x0001) {
- tmp = get_u8(frm);
+ tmp = p_get_u8(frm);
p_indent(level + 1, frm);
if (tmp & 0x80)
printf("16kHz ");
@@ -450,8 +452,8 @@ static inline void discover(int level, uint8_t hdr, struct frame *frm)
case 0x02:
while (frm->len > 1) {
p_indent(level, frm);
- seid = get_u8(frm);
- type = get_u8(frm);
+ seid = p_get_u8(frm);
+ type = p_get_u8(frm);
printf("ACP SEID %d - %s %s%s\n",
seid >> 2, media2str(type >> 4),
type & 0x08 ? "Sink" : "Source",
@@ -490,7 +492,7 @@ static inline void set_configuration(int level, uint8_t hdr, struct frame *frm)
break;
case 0x03:
p_indent(level, frm);
- cat = get_u8(frm);
+ cat = p_get_u8(frm);
printf("%s\n", cat2str(cat));
errorcode(level, frm);
break;
@@ -522,7 +524,7 @@ static inline void reconfigure(int level, uint8_t hdr, struct frame *frm)
break;
case 0x03:
p_indent(level, frm);
- cat = get_u8(frm);
+ cat = p_get_u8(frm);
printf("%s\n", cat2str(cat));
errorcode(level, frm);
break;
@@ -588,8 +590,8 @@ static inline void delay_report(int level, uint8_t hdr, struct frame *frm)
switch (hdr & 0x03) {
case 0x00:
p_indent(level, frm);
- seid = get_u8(frm);
- delay = get_u16(frm);
+ seid = p_get_u8(frm);
+ delay = p_get_u16(frm);
printf("ACP SEID %d delay %u.%ums\n", seid >> 2,
delay / 10, delay % 10);
break;
@@ -608,10 +610,10 @@ void avdtp_dump(int level, struct frame *frm)
switch (frm->num) {
case 1:
p_indent(level, frm);
- hdr = get_u8(frm);
+ hdr = p_get_u8(frm);
- nsp = (hdr & 0x0c) == 0x04 ? get_u8(frm) : 0;
- sid = hdr & 0x08 ? 0x00 : get_u8(frm);
+ nsp = (hdr & 0x0c) == 0x04 ? p_get_u8(frm) : 0;
+ sid = hdr & 0x08 ? 0x00 : p_get_u8(frm);
printf("AVDTP(s): %s %s: transaction %d nsp 0x%02x\n",
hdr & 0x08 ? pt2str(hdr) : si2str(sid),
@@ -661,11 +663,11 @@ void avdtp_dump(int level, struct frame *frm)
case 2:
p_indent(level, frm);
- hdr = get_u8(frm);
- type = get_u8(frm);
- seqn = get_u16(frm);
- time = get_u32(frm);
- ssrc = get_u32(frm);
+ hdr = p_get_u8(frm);
+ type = p_get_u8(frm);
+ seqn = p_get_u16(frm);
+ time = p_get_u32(frm);
+ ssrc = p_get_u32(frm);
printf("AVDTP(m): ver %d %s%scc %d %spt %d seqn %d time %d ssrc %d\n",
hdr >> 6, hdr & 0x20 ? "pad " : "", hdr & 0x10 ? "ext " : "",
diff --git a/tools/parser/avrcp.c b/tools/parser/avrcp.c
index 7c320ea7..5f292722 100644
--- a/tools/parser/avrcp.c
+++ b/tools/parser/avrcp.c
@@ -422,7 +422,7 @@ static void avrcp_rejected_dump(int level, struct frame *frm, uint16_t len)
return;
}
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Error: 0x%02x (%s)\n", status, error2str(status));
}
@@ -439,7 +439,7 @@ static void avrcp_get_capabilities_dump(int level, struct frame *frm, uint16_t l
return;
}
- cap = get_u8(frm);
+ cap = p_get_u8(frm);
printf("CapabilityID: 0x%02x (%s)\n", cap, cap2str(cap));
if (len == 1)
@@ -447,7 +447,7 @@ static void avrcp_get_capabilities_dump(int level, struct frame *frm, uint16_t l
p_indent(level, frm);
- count = get_u8(frm);
+ count = p_get_u8(frm);
printf("CapabilityCount: 0x%02x\n", count);
switch (cap) {
@@ -459,7 +459,7 @@ static void avrcp_get_capabilities_dump(int level, struct frame *frm, uint16_t l
printf("%s: 0x", cap2str(cap));
for (i = 0; i < 3; i++)
- printf("%02x", get_u8(frm));
+ printf("%02x", p_get_u8(frm));
printf("\n");
}
break;
@@ -469,7 +469,7 @@ static void avrcp_get_capabilities_dump(int level, struct frame *frm, uint16_t l
p_indent(level, frm);
- event = get_u8(frm);
+ event = p_get_u8(frm);
printf("%s: 0x%02x (%s)\n", cap2str(cap), event,
event2str(event));
}
@@ -507,7 +507,7 @@ static void avrcp_list_player_attributes_dump(int level, struct frame *frm,
p_indent(level, frm);
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("AttributeCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -515,7 +515,7 @@ static void avrcp_list_player_attributes_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
}
}
@@ -591,13 +591,13 @@ static void avrcp_list_player_values_dump(int level, struct frame *frm,
if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
goto response;
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
return;
response:
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("ValueCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -605,7 +605,7 @@ response:
p_indent(level, frm);
- value = get_u8(frm);
+ value = p_get_u8(frm);
printf("ValueID: 0x%02x (%s)\n", value,
value2str(attr, value));
}
@@ -627,7 +627,7 @@ static void avrcp_get_current_player_value_dump(int level, struct frame *frm,
if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
goto response;
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("AttributeCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -635,14 +635,14 @@ static void avrcp_get_current_player_value_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
}
return;
response:
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("ValueCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -650,12 +650,12 @@ response:
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
p_indent(level, frm);
- value = get_u8(frm);
+ value = p_get_u8(frm);
printf("ValueID: 0x%02x (%s)\n", value,
value2str(attr, value));
}
@@ -677,7 +677,7 @@ static void avrcp_set_player_value_dump(int level, struct frame *frm,
return;
}
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("AttributeCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -685,12 +685,12 @@ static void avrcp_set_player_value_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
p_indent(level, frm);
- value = get_u8(frm);
+ value = p_get_u8(frm);
printf("ValueID: 0x%02x (%s)\n", value,
value2str(attr, value));
}
@@ -742,7 +742,7 @@ static void avrcp_get_player_attribute_text_dump(int level, struct frame *frm,
return;
}
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("AttributeCount: 0x%02x\n", num);
if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
@@ -753,7 +753,7 @@ static void avrcp_get_player_attribute_text_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
}
@@ -766,25 +766,25 @@ response:
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset,
charset2str(charset));
p_indent(level, frm);
- len = get_u8(frm);
+ len = p_get_u8(frm);
printf("StringLength: 0x%02x\n", len);
p_indent(level, frm);
printf("String: ");
for (; len > 0; len--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -808,12 +808,12 @@ static void avrcp_get_player_value_text_dump(int level, struct frame *frm,
if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
goto response;
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
p_indent(level, frm);
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("ValueCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -821,7 +821,7 @@ static void avrcp_get_player_value_text_dump(int level, struct frame *frm,
p_indent(level, frm);
- value = get_u8(frm);
+ value = p_get_u8(frm);
printf("ValueID: 0x%02x (%s)\n", value,
value2str(attr, value));
}
@@ -829,7 +829,7 @@ static void avrcp_get_player_value_text_dump(int level, struct frame *frm,
return;
response:
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("ValueCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -838,26 +838,26 @@ response:
p_indent(level, frm);
- value = get_u8(frm);
+ value = p_get_u8(frm);
printf("ValueID: 0x%02x (%s)\n", value,
value2str(attr, value));
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset,
charset2str(charset));
p_indent(level, frm);
- len = get_u8(frm);
+ len = p_get_u8(frm);
printf("StringLength: 0x%02x\n", len);
p_indent(level, frm);
printf("String: ");
for (; len > 0; len--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -880,7 +880,7 @@ static void avrcp_displayable_charset(int level, struct frame *frm,
return;
}
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("CharsetCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -888,7 +888,7 @@ static void avrcp_displayable_charset(int level, struct frame *frm,
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset,
charset2str(charset));
}
@@ -922,7 +922,7 @@ static void avrcp_ct_battery_status_dump(int level, struct frame *frm,
p_indent(level, frm);
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("BatteryStatus: 0x%02x (%s)\n", status, status2str(status));
}
@@ -968,12 +968,12 @@ static void avrcp_get_element_attributes_dump(int level, struct frame *frm,
return;
}
- id = get_u64(frm);
+ id = p_get_u64(frm);
printf("Identifier: 0x%jx (%s)\n", id, id ? "Reserved" : "PLAYING");
p_indent(level, frm);
- num = get_u8(frm);
+ num = p_get_u8(frm);
printf("AttributeCount: 0x%02x\n", num);
for (; num > 0; num--) {
@@ -981,7 +981,7 @@ static void avrcp_get_element_attributes_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u32(frm);
+ attr = p_get_u32(frm);
printf("Attribute: 0x%08x (%s)\n", attr, mediattr2str(attr));
}
@@ -995,7 +995,7 @@ response:
return;
}
- num = get_u8(frm);
+ num = p_get_u8(frm);
avrcp_continuing.num = num;
printf("AttributeCount: 0x%02x\n", num);
len--;
@@ -1015,7 +1015,7 @@ response:
printf("ContinuingAttributeValue: ");
for (; size > 0; size--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -1030,17 +1030,17 @@ response:
p_indent(level, frm);
- attr = get_u32(frm);
+ attr = p_get_u32(frm);
printf("Attribute: 0x%08x (%s)\n", attr, mediattr2str(attr));
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset,
charset2str(charset));
p_indent(level, frm);
- attrlen = get_u16(frm);
+ attrlen = p_get_u16(frm);
printf("AttributeValueLength: 0x%04x\n", attrlen);
len -= sizeof(attr) + sizeof(charset) + sizeof(attrlen);
@@ -1050,7 +1050,7 @@ response:
printf("AttributeValue: ");
for (; attrlen > 0 && len > 0; attrlen--, len--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -1099,17 +1099,17 @@ static void avrcp_get_play_status_dump(int level, struct frame *frm,
return;
}
- interval = get_u32(frm);
+ interval = p_get_u32(frm);
printf("SongLength: 0x%08x (%u miliseconds)\n", interval, interval);
p_indent(level, frm);
- interval = get_u32(frm);
+ interval = p_get_u32(frm);
printf("SongPosition: 0x%08x (%u miliconds)\n", interval, interval);
p_indent(level, frm);
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("PlayStatus: 0x%02x (%s)\n", status, playstatus2str(status));
}
@@ -1132,12 +1132,12 @@ static void avrcp_register_notification_dump(int level, struct frame *frm,
return;
}
- event = get_u8(frm);
+ event = p_get_u8(frm);
printf("EventID: 0x%02x (%s)\n", event, event2str(event));
p_indent(level, frm);
- interval = get_u32(frm);
+ interval = p_get_u32(frm);
printf("Interval: 0x%08x (%u seconds)\n", interval, interval);
return;
@@ -1149,33 +1149,33 @@ response:
return;
}
- event = get_u8(frm);
+ event = p_get_u8(frm);
printf("EventID: 0x%02x (%s)\n", event, event2str(event));
p_indent(level, frm);
switch (event) {
case AVRCP_EVENT_PLAYBACK_STATUS_CHANGED:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("PlayStatus: 0x%02x (%s)\n", status,
playstatus2str(status));
break;
case AVRCP_EVENT_TRACK_CHANGED:
- id = get_u64(frm);
+ id = p_get_u64(frm);
printf("Identifier: 0x%16" PRIx64 " (%" PRIu64 ")\n", id, id);
break;
case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
- interval = get_u32(frm);
+ interval = p_get_u32(frm);
printf("Position: 0x%08x (%u miliseconds)\n", interval,
interval);
break;
case AVRCP_EVENT_BATT_STATUS_CHANGED:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("BatteryStatus: 0x%02x (%s)\n", status,
status2str(status));
break;
case AVRCP_EVENT_SYSTEM_STATUS_CHANGED:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("SystemStatus: 0x%02x ", status);
switch (status) {
case 0x00:
@@ -1193,7 +1193,7 @@ response:
}
break;
case AVRCP_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("AttributeCount: 0x%02x\n", status);
for (; status > 0; status--) {
@@ -1201,33 +1201,33 @@ response:
p_indent(level, frm);
- attr = get_u8(frm);
+ attr = p_get_u8(frm);
printf("AttributeID: 0x%02x (%s)\n", attr,
attr2str(attr));
p_indent(level, frm);
- value = get_u8(frm);
+ value = p_get_u8(frm);
printf("ValueID: 0x%02x (%s)\n", value,
value2str(attr, value));
}
break;
case AVRCP_EVENT_VOLUME_CHANGED:
- status = get_u8(frm) & 0x7F;
+ status = p_get_u8(frm) & 0x7F;
printf("Volume: %.2f%% (%d/127)\n", status/1.27, status);
break;
case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
- uid = get_u16(frm);
+ uid = p_get_u16(frm);
printf("PlayerID: 0x%04x (%u)\n", uid, uid);
p_indent(level, frm);
- uid = get_u16(frm);
+ uid = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uid, uid);
break;
case AVRCP_EVENT_UIDS_CHANGED:
- uid = get_u16(frm);
+ uid = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uid, uid);
break;
}
@@ -1246,7 +1246,7 @@ static void avrcp_set_absolute_volume_dump(int level, struct frame *frm,
return;
}
- value = get_u8(frm) & 0x7F;
+ value = p_get_u8(frm) & 0x7F;
printf("Volume: %.2f%% (%d/127)\n", value/1.27, value);
}
@@ -1267,7 +1267,7 @@ static void avrcp_set_addressed_player(int level, struct frame *frm,
return;
}
- id = get_u16(frm);
+ id = p_get_u16(frm);
printf("PlayerID: 0x%04x (%u)\n", id, id);
return;
@@ -1278,7 +1278,7 @@ response:
return;
}
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
}
@@ -1300,7 +1300,7 @@ static void avrcp_set_browsed_player_dump(int level, struct frame *frm,
return;
}
- id = get_u16(frm);
+ id = p_get_u16(frm);
printf("PlayerID: 0x%04x (%u)\n", id, id);
return;
@@ -1311,7 +1311,7 @@ response:
return;
}
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
if (len == 1)
@@ -1319,22 +1319,22 @@ response:
p_indent(level, frm);
- uids = get_u16(frm);
+ uids = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uids, uids);
p_indent(level, frm);
- items = get_u32(frm);
+ items = p_get_u32(frm);
printf("Number of Items: 0x%08x (%u)\n", items, items);
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
p_indent(level, frm);
- folders = get_u8(frm);
+ folders = p_get_u8(frm);
printf("Folder Depth: 0x%02x (%u)\n", folders, folders);
for (; folders > 0; folders--) {
@@ -1342,10 +1342,10 @@ response:
p_indent(level, frm);
- len = get_u8(frm);
+ len = p_get_u8(frm);
printf("Folder: ");
for (; len > 0; len--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -1386,23 +1386,23 @@ static void avrcp_play_item_dump(int level, struct frame *frm,
return;
}
- scope = get_u8(frm);
+ scope = p_get_u8(frm);
printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
p_indent(level, frm);
- uid = get_u64(frm);
+ uid = p_get_u64(frm);
printf("UID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
p_indent(level, frm);
- uidcounter = get_u16(frm);
+ uidcounter = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
}
@@ -1424,23 +1424,23 @@ static void avrcp_add_to_now_playing_dump(int level, struct frame *frm,
return;
}
- scope = get_u8(frm);
+ scope = p_get_u8(frm);
printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
p_indent(level, frm);
- uid = get_u64(frm);
+ uid = p_get_u64(frm);
printf("UID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
p_indent(level, frm);
- uidcounter = get_u16(frm);
+ uidcounter = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
}
@@ -1451,9 +1451,9 @@ static void avrcp_pdu_dump(int level, struct frame *frm, uint8_t ctype)
p_indent(level, frm);
- pduid = get_u8(frm);
- pt = get_u8(frm);
- len = get_u16(frm);
+ pduid = p_get_u8(frm);
+ pt = p_get_u8(frm);
+ len = p_get_u16(frm);
printf("AVRCP: %s: pt %s len 0x%04x\n", pdu2str(pduid),
pt2str(pt), len);
@@ -1566,13 +1566,13 @@ static void avrcp_passthrough_dump(int level, struct frame *frm)
p_indent(level, frm);
- op = get_u8(frm);
+ op = p_get_u8(frm);
printf("Operation: 0x%02x (%s %s)\n", op, op2str(op),
op & 0x80 ? "Released" : "Pressed");
p_indent(level, frm);
- len = get_u8(frm);
+ len = p_get_u8(frm);
printf("Lenght: 0x%02x\n", len);
@@ -1683,46 +1683,46 @@ static void avrcp_media_player_item_dump(int level, struct frame *frm,
return;
}
- id = get_u16(frm);
+ id = p_get_u16(frm);
printf("PlayerID: 0x%04x (%u)\n", id, id);
p_indent(level, frm);
- type = get_u8(frm);
+ type = p_get_u8(frm);
printf("PlayerType: 0x%04x (%s)\n", type, playertype2str(type));
p_indent(level, frm);
- subtype = get_u32(frm);
+ subtype = p_get_u32(frm);
printf("PlayerSubtype: 0x%08x (%s)\n", subtype,
playersubtype2str(subtype));
p_indent(level, frm);
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("PlayStatus: 0x%02x (%s)\n", status, playstatus2str(status));
p_indent(level, frm);
- get_u128(frm, &features[0], &features[1]);
+ p_get_u128(frm, &features[0], &features[1]);
printf("Features: 0x%16" PRIx64 "%16" PRIx64 "\n", features[1],
features[0]);
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
p_indent(level, frm);
- namelen = get_u16(frm);
+ namelen = p_get_u16(frm);
printf("NameLength: 0x%04x (%u)\n", namelen, namelen);
p_indent(level, frm);
printf("Name: ");
for (; namelen > 0; namelen--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -1764,35 +1764,35 @@ static void avrcp_folder_item_dump(int level, struct frame *frm, uint16_t len)
return;
}
- uid = get_u64(frm);
+ uid = p_get_u64(frm);
printf("FolderUID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
p_indent(level, frm);
- type = get_u8(frm);
+ type = p_get_u8(frm);
printf("FolderType: 0x%02x (%s)\n", type, foldertype2str(type));
p_indent(level, frm);
- playable = get_u8(frm);
+ playable = p_get_u8(frm);
printf("IsPlayable: 0x%02x (%s)\n", playable,
playable & 0x01 ? "True" : "False");
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
p_indent(level, frm);
- namelen = get_u16(frm);
+ namelen = p_get_u16(frm);
printf("NameLength: 0x%04x (%u)\n", namelen, namelen);
p_indent(level, frm);
printf("Name: ");
for (; namelen > 0; namelen--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -1820,25 +1820,25 @@ static void avrcp_attribute_entry_list_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u32(frm);
+ attr = p_get_u32(frm);
printf("AttributeID: 0x%08x (%s)\n", attr, mediattr2str(attr));
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset,
charset2str(charset));
p_indent(level, frm);
- len = get_u16(frm);
+ len = p_get_u16(frm);
printf("AttributeLength: 0x%04x (%u)\n", len, len);
p_indent(level, frm);
printf("AttributeValue: ");
for (; len > 0; len--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -1860,36 +1860,36 @@ static void avrcp_media_element_item_dump(int level, struct frame *frm,
return;
}
- uid = get_u64(frm);
+ uid = p_get_u64(frm);
printf("ElementUID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
p_indent(level, frm);
- type = get_u8(frm);
+ type = p_get_u8(frm);
printf("ElementType: 0x%02x (%s)\n", type, elementtype2str(type));
p_indent(level, frm);
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
p_indent(level, frm);
- namelen = get_u16(frm);
+ namelen = p_get_u16(frm);
printf("NameLength: 0x%04x (%u)\n", namelen, namelen);
p_indent(level, frm);
printf("Name: ");
for (; namelen > 0; namelen--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
p_indent(level, frm);
- count = get_u8(frm);
+ count = p_get_u8(frm);
printf("AttributeCount: 0x%02x (%u)\n", count, count);
avrcp_attribute_entry_list_dump(level, frm, count);
@@ -1913,22 +1913,22 @@ static void avrcp_get_folder_items_dump(int level, struct frame *frm,
return;
}
- scope = get_u8(frm);
+ scope = p_get_u8(frm);
printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
p_indent(level, frm);
- start = get_u32(frm);
+ start = p_get_u32(frm);
printf("StartItem: 0x%08x (%u)\n", start, start);
p_indent(level, frm);
- end = get_u32(frm);
+ end = p_get_u32(frm);
printf("EndItem: 0x%08x (%u)\n", end, end);
p_indent(level, frm);
- count = get_u8(frm);
+ count = p_get_u8(frm);
printf("AttributeCount: 0x%02x (%u)\n", count, count);
for (; count > 0; count--) {
@@ -1936,14 +1936,14 @@ static void avrcp_get_folder_items_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u32(frm);
+ attr = p_get_u32(frm);
printf("AttributeID: 0x%08x (%s)\n", attr, mediattr2str(attr));
}
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
if (len == 1)
@@ -1951,12 +1951,12 @@ response:
p_indent(level, frm);
- uid = get_u16(frm);
+ uid = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uid, uid);
p_indent(level, frm);
- num = get_u16(frm);
+ num = p_get_u16(frm);
printf("Number of Items: 0x%04x (%u)\n", num, num);
for (; num > 0; num--) {
@@ -1965,8 +1965,8 @@ response:
p_indent(level, frm);
- type = get_u8(frm);
- len = get_u16(frm);
+ type = p_get_u8(frm);
+ len = p_get_u16(frm);
switch (type) {
case 0x01:
printf("Item: 0x01 (Media Player)) ");
@@ -2018,23 +2018,23 @@ static void avrcp_change_path_dump(int level, struct frame *frm, uint8_t hdr,
return;
}
- uidcounter = get_u16(frm);
+ uidcounter = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
p_indent(level, frm);
- dir = get_u8(frm);
+ dir = p_get_u8(frm);
printf("Direction: 0x%02x (%s)\n", dir, dir2str(dir));
p_indent(level, frm);
- uid = get_u64(frm);
+ uid = p_get_u64(frm);
printf("FolderUID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
if (len == 1)
@@ -2042,7 +2042,7 @@ response:
p_indent(level, frm);
- items = get_u32(frm);
+ items = p_get_u32(frm);
printf("Number of Items: 0x%04x (%u)", items, items);
}
@@ -2064,22 +2064,22 @@ static void avrcp_get_item_attributes_dump(int level, struct frame *frm,
return;
}
- scope = get_u8(frm);
+ scope = p_get_u8(frm);
printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
p_indent(level, frm);
- uid = get_u64(frm);
+ uid = p_get_u64(frm);
printf("UID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
p_indent(level, frm);
- uidcounter = get_u16(frm);
+ uidcounter = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
p_indent(level, frm);
- count = get_u8(frm);
+ count = p_get_u8(frm);
printf("AttributeCount: 0x%02x (%u)\n", count, count);
for (; count > 0; count--) {
@@ -2087,14 +2087,14 @@ static void avrcp_get_item_attributes_dump(int level, struct frame *frm,
p_indent(level, frm);
- attr = get_u32(frm);
+ attr = p_get_u32(frm);
printf("AttributeID: 0x%08x (%s)\n", attr, mediattr2str(attr));
}
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
if (len == 1)
@@ -2102,7 +2102,7 @@ response:
p_indent(level, frm);
- count = get_u8(frm);
+ count = p_get_u8(frm);
printf("AttributeCount: 0x%02x (%u)\n", count, count);
avrcp_attribute_entry_list_dump(level, frm, count);
@@ -2126,19 +2126,19 @@ static void avrcp_search_dump(int level, struct frame *frm, uint8_t hdr,
return;
}
- charset = get_u16(frm);
+ charset = p_get_u16(frm);
printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
p_indent(level, frm);
- namelen = get_u16(frm);
+ namelen = p_get_u16(frm);
printf("Length: 0x%04x (%u)\n", namelen, namelen);
p_indent(level, frm);
printf("String: ");
for (; namelen > 0; namelen--) {
- uint8_t c = get_u8(frm);
+ uint8_t c = p_get_u8(frm);
printf("%1c", isprint(c) ? c : '.');
}
printf("\n");
@@ -2146,7 +2146,7 @@ static void avrcp_search_dump(int level, struct frame *frm, uint8_t hdr,
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
if (len == 1)
@@ -2154,12 +2154,12 @@ response:
p_indent(level, frm);
- uidcounter = get_u16(frm);
+ uidcounter = p_get_u16(frm);
printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
p_indent(level, frm);
- items = get_u32(frm);
+ items = p_get_u32(frm);
printf("Number of Items: 0x%04x (%u)", items, items);
}
@@ -2178,7 +2178,7 @@ static void avrcp_general_reject_dump(int level, struct frame *frm,
return;
response:
- status = get_u8(frm);
+ status = p_get_u8(frm);
printf("Status: 0x%02x (%s)\n", status, error2str(status));
}
@@ -2187,8 +2187,8 @@ static void avrcp_browsing_dump(int level, struct frame *frm, uint8_t hdr)
uint8_t pduid;
uint16_t len;
- pduid = get_u8(frm);
- len = get_u16(frm);
+ pduid = p_get_u8(frm);
+ len = p_get_u16(frm);
printf("AVRCP: %s: len 0x%04x\n", pdu2str(pduid), len);
@@ -2228,9 +2228,9 @@ static void avrcp_control_dump(int level, struct frame *frm)
uint8_t ctype, address, subunit, opcode, company[3];
int i;
- ctype = get_u8(frm);
- address = get_u8(frm);
- opcode = get_u8(frm);
+ ctype = p_get_u8(frm);
+ address = p_get_u8(frm);
+ opcode = p_get_u8(frm);
printf("AV/C: %s: address 0x%02x opcode 0x%02x\n", ctype2str(ctype),
address, opcode);
@@ -2265,7 +2265,7 @@ static void avrcp_control_dump(int level, struct frame *frm)
printf("Company ID: 0x");
for (i = 0; i < 3; i++) {
- company[i] = get_u8(frm);
+ company[i] = p_get_u8(frm);
printf("%02x", company[i]);
}
printf("\n");
diff --git a/tools/parser/bnep.c b/tools/parser/bnep.c
index d9e958d7..7c549f40 100644
--- a/tools/parser/bnep.c
+++ b/tools/parser/bnep.c
@@ -79,48 +79,48 @@ static void bnep_control(int level, struct frame *frm, int header_length)
int i, length;
char *s;
uint32_t uuid = 0;
- uint8_t type = get_u8(frm);
+ uint8_t type = p_get_u8(frm);
p_indent(++level, frm);
switch (type) {
case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
- printf("Not Understood(0x%02x) type 0x%02x\n", type, get_u8(frm));
+ printf("Not Understood(0x%02x) type 0x%02x\n", type, p_get_u8(frm));
break;
case BNEP_SETUP_CONNECTION_REQUEST_MSG:
- uuid_size = get_u8(frm);
+ uuid_size = p_get_u8(frm);
printf("Setup Req(0x%02x) size 0x%02x ", type, uuid_size);
switch (uuid_size) {
case 2:
- uuid = get_u16(frm);
+ uuid = p_get_u16(frm);
printf("dst 0x%x", uuid);
if ((s = get_uuid_name(uuid)) != 0)
printf("(%s)", s);
- uuid = get_u16(frm);
+ uuid = p_get_u16(frm);
printf(" src 0x%x", uuid);
if ((s = get_uuid_name(uuid)) != 0)
printf("(%s)", s);
printf("\n");
break;
case 4:
- uuid = get_u32(frm);
+ uuid = p_get_u32(frm);
printf("dst 0x%x", uuid);
if ((s = get_uuid_name(uuid)) != 0)
printf("(%s)", s);
- uuid = get_u32(frm);
+ uuid = p_get_u32(frm);
printf(" src 0x%x", uuid);
if ((s = get_uuid_name(uuid)) != 0)
printf("(%s)", s);
printf("\n");
break;
case 16:
- uuid = get_u32(frm);
+ uuid = p_get_u32(frm);
printf("dst 0x%x", uuid);
if ((s = get_uuid_name(uuid)) != 0)
printf("(%s)", s);
frm->ptr += 12;
frm->len -= 12;
- uuid = get_u32(frm);
+ uuid = p_get_u32(frm);
printf(" src 0x%x", uuid);
if ((s = get_uuid_name(uuid)) != 0)
printf("(%s)", s);
@@ -137,27 +137,27 @@ static void bnep_control(int level, struct frame *frm, int header_length)
case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
printf("Setup Rsp(0x%02x) res 0x%04x\n",
- type, get_u16(frm));
+ type, p_get_u16(frm));
break;
case BNEP_FILTER_NET_TYPE_SET_MSG:
- length = get_u16(frm);
+ length = p_get_u16(frm);
printf("Filter NetType Set(0x%02x) len 0x%04x\n",
type, length);
for (i = 0; i < length / 4; i++) {
p_indent(level + 1, frm);
- printf("0x%04x - ", get_u16(frm));
- printf("0x%04x\n", get_u16(frm));
+ printf("0x%04x - ", p_get_u16(frm));
+ printf("0x%04x\n", p_get_u16(frm));
}
break;
case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
printf("Filter NetType Rsp(0x%02x) res 0x%04x\n",
- type, get_u16(frm));
+ type, p_get_u16(frm));
break;
case BNEP_FILTER_MULT_ADDR_SET_MSG:
- length = get_u16(frm);
+ length = p_get_u16(frm);
printf("Filter MultAddr Set(0x%02x) len 0x%04x\n",
type, length);
for (i = 0; i < length / 12; i++) {
@@ -169,7 +169,7 @@ static void bnep_control(int level, struct frame *frm, int header_length)
case BNEP_FILTER_MULT_ADDR_RESPONSE_MSG:
printf("Filter MultAddr Rsp(0x%02x) res 0x%04x\n",
- type, get_u16(frm));
+ type, p_get_u16(frm));
break;
default:
@@ -183,8 +183,8 @@ static void bnep_control(int level, struct frame *frm, int header_length)
static void bnep_eval_extension(int level, struct frame *frm)
{
- uint8_t type = get_u8(frm);
- uint8_t length = get_u8(frm);
+ uint8_t type = p_get_u8(frm);
+ uint8_t length = p_get_u8(frm);
int extension = type & 0x80;
p_indent(level, frm);
@@ -210,7 +210,7 @@ static void bnep_eval_extension(int level, struct frame *frm)
void bnep_dump(int level, struct frame *frm)
{
- uint8_t type = get_u8(frm);
+ uint8_t type = p_get_u8(frm);
uint16_t proto = 0x0000;
int extension = type & 0x80;
@@ -227,7 +227,7 @@ void bnep_dump(int level, struct frame *frm)
printf("BNEP: Compressed(0x%02x|%s)\n",
type & 0x7f, extension ? "1" : "0");
p_indent(++level, frm);
- proto = get_u16(frm);
+ proto = p_get_u16(frm);
printf("[proto 0x%04x]\n", proto);
break;
@@ -237,7 +237,7 @@ void bnep_dump(int level, struct frame *frm)
p_indent(++level, frm);
printf("dst %s ", get_macaddr(frm));
printf("src %s ", get_macaddr(frm));
- proto = get_u16(frm);
+ proto = p_get_u16(frm);
printf("[proto 0x%04x]\n", proto);
break;
@@ -246,7 +246,7 @@ void bnep_dump(int level, struct frame *frm)
type & 0x7f, extension ? "1" : "0");
p_indent(++level, frm);
printf("dst %s ", get_macaddr(frm));
- proto = get_u16(frm);
+ proto = p_get_u16(frm);
printf("[proto 0x%04x]\n", proto);
break;
@@ -255,7 +255,7 @@ void bnep_dump(int level, struct frame *frm)
type & 0x7f, extension ? "1" : "0");
p_indent(++level, frm);
printf("src %s ", get_macaddr(frm));
- proto = get_u16(frm);
+ proto = p_get_u16(frm);
printf("[proto 0x%04x]\n", proto);
break;
@@ -275,8 +275,8 @@ void bnep_dump(int level, struct frame *frm)
/* 802.1p header */
if (proto == 0x8100) {
p_indent(level, frm);
- printf("802.1p Header: 0x%04x ", get_u16(frm));
- proto = get_u16(frm);
+ printf("802.1p Header: 0x%04x ", p_get_u16(frm));
+ proto = p_get_u16(frm);
printf("[proto 0x%04x]\n", proto);
}
diff --git a/tools/parser/bpa.c b/tools/parser/bpa.c
index 207397f4..74a3457e 100644
--- a/tools/parser/bpa.c
+++ b/tools/parser/bpa.c
@@ -33,9 +33,9 @@
#include "parser.h"
-#define BPA_U8(frm) (get_u8(frm))
-#define BPA_U16(frm) (btohs(htons(get_u16(frm))))
-#define BPA_U32(frm) (btohl(htonl(get_u32(frm))))
+#define BPA_U8(frm) (p_get_u8(frm))
+#define BPA_U16(frm) (btohs(htons(p_get_u16(frm))))
+#define BPA_U32(frm) (btohl(htonl(p_get_u32(frm))))
void bpa_dump(int level, struct frame *frm)
{
@@ -43,13 +43,13 @@ void bpa_dump(int level, struct frame *frm)
uint16_t num, len;
uint32_t time;
- id = get_u8(frm);
- num = get_u16(frm);
+ id = p_get_u8(frm);
+ num = p_get_u16(frm);
len = BPA_U16(frm);
- status = get_u8(frm);
- time = get_u32(frm);
- channel = get_u8(frm);
+ status = p_get_u8(frm);
+ time = p_get_u32(frm);
+ channel = p_get_u8(frm);
p_indent(level, frm);
printf("BPA: id %d num %d len %u status 0x%02x time %d channel %d\n",
diff --git a/tools/parser/capi.c b/tools/parser/capi.c
index 97abc4c1..b8d05c25 100644
--- a/tools/parser/capi.c
+++ b/tools/parser/capi.c
@@ -34,9 +34,9 @@
#include "parser.h"
-#define CAPI_U8(frm) (get_u8(frm))
-#define CAPI_U16(frm) (btohs(htons(get_u16(frm))))
-#define CAPI_U32(frm) (btohl(htonl(get_u32(frm))))
+#define CAPI_U8(frm) (p_get_u8(frm))
+#define CAPI_U16(frm) (btohs(htons(p_get_u16(frm))))
+#define CAPI_U32(frm) (btohl(htonl(p_get_u32(frm))))
static char *cmd2str(uint8_t cmd)
{
@@ -718,7 +718,7 @@ static void cmd_data_b3(int level, uint8_t subcmd, struct frame *frm)
printf("Flags: 0x%04x\n", flags);
if (data == 0)
- (void) get_u64(frm);
+ (void) p_get_u64(frm);
raw_dump(level, frm);
}
diff --git a/tools/parser/cmtp.c b/tools/parser/cmtp.c
index ac5cf840..ed5d13b5 100644
--- a/tools/parser/cmtp.c
+++ b/tools/parser/cmtp.c
@@ -161,15 +161,15 @@ void cmtp_dump(int level, struct frame *frm)
while (frm->len > 0) {
- hdr = get_u8(frm);
+ hdr = p_get_u8(frm);
bid = (hdr & 0x3c) >> 2;
switch ((hdr & 0xc0) >> 6) {
case 0x01:
- len = get_u8(frm);
+ len = p_get_u8(frm);
break;
case 0x02:
- len = htons(get_u16(frm));
+ len = htons(p_get_u16(frm));
break;
default:
len = 0;
diff --git a/tools/parser/csr.c b/tools/parser/csr.c
index 1a63ae09..a0a4eb5f 100644
--- a/tools/parser/csr.c
+++ b/tools/parser/csr.c
@@ -33,10 +33,10 @@
#include "parser.h"
-#define CSR_U8(frm) (get_u8(frm))
-#define CSR_U16(frm) (btohs(htons(get_u16(frm))))
+#define CSR_U8(frm) (p_get_u8(frm))
+#define CSR_U16(frm) (btohs(htons(p_get_u16(frm))))
#define CSR_U32(frm) ((CSR_U16(frm) << 16) + CSR_U16(frm))
-#define CSR_S16(frm) (btohs(htons(get_u16(frm))))
+#define CSR_S16(frm) (btohs(htons(p_get_u16(frm))))
static char *type2str(uint16_t type)
{
diff --git a/tools/parser/ericsson.c b/tools/parser/ericsson.c
index a401959f..3d52411b 100644
--- a/tools/parser/ericsson.c
+++ b/tools/parser/ericsson.c
@@ -32,7 +32,7 @@
void ericsson_dump(int level, struct frame *frm)
{
- uint8_t event = get_u8(frm);
+ uint8_t event = p_get_u8(frm);
uint8_t *buf = (uint8_t *) frm->ptr;
if (event != 0x10) {
diff --git a/tools/parser/hci.c b/tools/parser/hci.c
index 0918eeea..8c7bd258 100644
--- a/tools/parser/hci.c
+++ b/tools/parser/hci.c
@@ -127,7 +127,7 @@ static char *event_str[EVENT_NUM + 1] = {
"AMP Status Change",
};
-#define LE_EV_NUM 11
+#define LE_EV_NUM 5
static char *ev_le_meta_str[LE_EV_NUM + 1] = {
"Unknown",
"LE Connection Complete",
@@ -135,12 +135,6 @@ static char *ev_le_meta_str[LE_EV_NUM + 1] = {
"LE Connection Update Complete",
"LE Read Remote Used Features Complete",
"LE Long Term Key Request",
- "LE Remote Connection Parameter Request",
- "LE Data Length Change",
- "LE Read Local P-256 Public Key Complete",
- "LE Generate DHKey Complete",
- "LE Enhanced Connection Complete",
- "LE Direct Advertising Report",
};
#define CMD_LINKCTL_NUM 60
@@ -839,7 +833,7 @@ static inline void ext_inquiry_response_dump(int level, struct frame *frm)
uint8_t length;
data = frm->ptr;
- length = get_u8(frm);
+ length = p_get_u8(frm);
while (length > 0) {
ext_inquiry_data_dump(level, frm, data);
@@ -848,7 +842,7 @@ static inline void ext_inquiry_response_dump(int level, struct frame *frm)
frm->len -= length;
data = frm->ptr;
- length = get_u8(frm);
+ length = p_get_u8(frm);
}
frm->ptr = ptr +
@@ -874,7 +868,7 @@ static inline void bdaddr_command_dump(int level, struct frame *frm)
static inline void generic_command_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle %d\n", handle);
@@ -884,7 +878,7 @@ static inline void generic_command_dump(int level, struct frame *frm)
static inline void generic_write_mode_dump(int level, struct frame *frm)
{
- uint8_t mode = get_u8(frm);
+ uint8_t mode = p_get_u8(frm);
p_indent(level, frm);
printf("mode 0x%2.2x\n", mode);
@@ -1219,7 +1213,7 @@ static inline void write_link_policy_dump(int level, struct frame *frm)
static inline void write_default_link_policy_dump(int level, struct frame *frm)
{
- uint16_t policy = btohs(htons(get_u16(frm)));
+ uint16_t policy = btohs(htons(p_get_u16(frm)));
char *str;
p_indent(level, frm);
@@ -1333,7 +1327,7 @@ static inline void request_stored_link_key_dump(int level, struct frame *frm)
static inline void return_link_keys_dump(int level, struct frame *frm)
{
- uint8_t num = get_u8(frm);
+ uint8_t num = p_get_u8(frm);
uint8_t key[16];
char addr[18];
int i, n;
@@ -1414,7 +1408,7 @@ static inline void write_current_iac_lap_dump(int level, struct frame *frm)
static inline void write_scan_enable_dump(int level, struct frame *frm)
{
- uint8_t enable = get_u8(frm);
+ uint8_t enable = p_get_u8(frm);
p_indent(level, frm);
printf("enable %d\n", enable);
@@ -1560,13 +1554,13 @@ static inline void host_buffer_size_dump(int level, struct frame *frm)
static inline void num_comp_pkts_dump(int level, struct frame *frm)
{
- uint8_t num = get_u8(frm);
+ uint8_t num = p_get_u8(frm);
uint16_t handle, packets;
int i;
for (i = 0; i < num; i++) {
- handle = btohs(htons(get_u16(frm)));
- packets = btohs(htons(get_u16(frm)));
+ handle = btohs(htons(p_get_u16(frm)));
+ packets = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle %d packets %d\n", handle, packets);
@@ -1701,7 +1695,7 @@ static inline void command_dump(int level, struct frame *frm)
return;
p_indent(level, frm);
- printf("HCI Command: %s (0x%2.2x|0x%4.4x) plen %d\n",
+ printf("HCI Command: %s (0x%2.2x|0x%4.4x) plen %d\n",
opcode2str(opcode), ogf, ocf, hdr->plen);
frm->ptr += HCI_COMMAND_HDR_SIZE;
@@ -2012,7 +2006,7 @@ static inline void command_dump(int level, struct frame *frm)
static inline void status_response_dump(int level, struct frame *frm)
{
- uint8_t status = get_u8(frm);
+ uint8_t status = p_get_u8(frm);
p_indent(level, frm);
printf("status 0x%2.2x\n", status);
@@ -2027,7 +2021,7 @@ static inline void status_response_dump(int level, struct frame *frm)
static inline void handle_response_dump(int level, struct frame *frm)
{
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("handle %d\n", handle);
@@ -2037,7 +2031,7 @@ static inline void handle_response_dump(int level, struct frame *frm)
static inline void bdaddr_response_dump(int level, struct frame *frm)
{
- uint8_t status = get_u8(frm);
+ uint8_t status = p_get_u8(frm);
bdaddr_t *bdaddr = frm->ptr;
char addr[18];
@@ -2076,8 +2070,8 @@ static inline void read_data_block_size_dump(int level, struct frame *frm)
static inline void generic_response_dump(int level, struct frame *frm)
{
- uint8_t status = get_u8(frm);
- uint16_t handle = btohs(htons(get_u16(frm)));
+ uint8_t status = p_get_u8(frm);
+ uint16_t handle = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
printf("status 0x%2.2x handle %d\n", status, handle);
@@ -2092,8 +2086,8 @@ static inline void generic_response_dump(int level, struct frame *frm)
static inline void status_mode_dump(int level, struct frame *frm)
{
- uint8_t status = get_u8(frm);
- uint8_t mode = get_u8(frm);
+ uint8_t status = p_get_u8(frm);
+ uint8_t mode = p_get_u8(frm);
p_indent(level, frm);
printf("status 0x%2.2x mode 0x%2.2x\n", status, mode);
@@ -2129,8 +2123,8 @@ static inline void read_link_policy_dump(int level, struct frame *frm)
static inline void read_default_link_policy_dump(int level, struct frame *frm)
{
- uint8_t status = get_u8(frm);
- uint16_t policy = btohs(htons(get_u16(frm)));
+ uint8_t status = p_get_u8(frm);
+ uint16_t policy = btohs(htons(p_get_u16(frm)));
char *str;
p_indent(level, frm);
@@ -2276,8 +2270,8 @@ static inline void read_current_iac_lap_dump(int level, struct frame *frm)
static inline void read_scan_enable_dump(int level, struct frame *frm)
{
- uint8_t status = get_u8(frm);
- uint8_t enable = get_u8(frm);
+ uint8_t status = p_get_u8(frm);
+ uint8_t enable = p_get_u8(frm);
p_indent(level, frm);
printf("status 0x%2.2x enable %d\n", status, enable);
@@ -3041,7 +3035,7 @@ static inline void hardware_error_dump(int level, struct frame *frm)
static inline void inq_result_dump(int level, struct frame *frm)
{
- uint8_t num = get_u8(frm);
+ uint8_t num = p_get_u8(frm);
char addr[18];
int i;
@@ -3389,7 +3383,7 @@ static inline void flow_spec_complete_dump(int level, struct frame *frm)
static inline void inq_result_with_rssi_dump(int level, struct frame *frm)
{
- uint8_t num = get_u8(frm);
+ uint8_t num = p_get_u8(frm);
char addr[18];
int i;
@@ -3508,7 +3502,7 @@ static inline void sniff_subrating_event_dump(int level, struct frame *frm)
static inline void extended_inq_result_dump(int level, struct frame *frm)
{
- uint8_t num = get_u8(frm);
+ uint8_t num = p_get_u8(frm);
char addr[18];
int i;
@@ -3592,7 +3586,7 @@ static inline void evt_le_conn_complete_dump(int level, struct frame *frm)
static inline void evt_le_advertising_report_dump(int level, struct frame *frm)
{
- uint8_t num_reports = get_u8(frm);
+ uint8_t num_reports = p_get_u8(frm);
const uint8_t RSSI_SIZE = 1;
while (num_reports--) {
@@ -3673,11 +3667,7 @@ static inline void le_meta_ev_dump(int level, struct frame *frm)
frm->len -= EVT_LE_META_EVENT_SIZE;
p_indent(level, frm);
-
- if (subevent <= LE_EV_NUM)
- printf("%s\n", ev_le_meta_str[subevent]);
- else
- printf("%s\n", ev_le_meta_str[0]);
+ printf("%s\n", ev_le_meta_str[subevent]);
switch (mevt->subevent) {
case EVT_LE_CONN_COMPLETE:
@@ -4084,10 +4074,10 @@ static inline void vendor_dump(int level, struct frame *frm)
return;
if (frm->dev_id == HCI_DEV_NONE) {
- uint16_t device = btohs(htons(get_u16(frm)));
- uint16_t proto = btohs(htons(get_u16(frm)));
- uint16_t type = btohs(htons(get_u16(frm)));
- uint16_t plen = btohs(htons(get_u16(frm)));
+ uint16_t device = btohs(htons(p_get_u16(frm)));
+ uint16_t proto = btohs(htons(p_get_u16(frm)));
+ uint16_t type = btohs(htons(p_get_u16(frm)));
+ uint16_t plen = btohs(htons(p_get_u16(frm)));
p_indent(level, frm);
diff --git a/tools/parser/hcrp.c b/tools/parser/hcrp.c
index 0a16a226..444ec23e 100644
--- a/tools/parser/hcrp.c
+++ b/tools/parser/hcrp.c
@@ -82,9 +82,9 @@ void hcrp_dump(int level, struct frame *frm)
uint16_t pid, tid, plen, status;
uint32_t credits;
- pid = get_u16(frm);
- tid = get_u16(frm);
- plen = get_u16(frm);
+ pid = p_get_u16(frm);
+ tid = p_get_u16(frm);
+ plen = p_get_u16(frm);
p_indent(level, frm);
@@ -92,19 +92,19 @@ void hcrp_dump(int level, struct frame *frm)
pid2str(pid), frm->in ? "rsp" : "cmd", tid, plen);
if (frm->in) {
- status = get_u16(frm);
+ status = p_get_u16(frm);
printf(" status %d (%s)\n", status, status2str(status));
} else
printf("\n");
if (pid == 0x0001 && !frm->in) {
- credits = get_u32(frm);
+ credits = p_get_u32(frm);
p_indent(level + 1, frm);
printf("credits %d\n", credits);
}
if (pid == 0x0002 && frm->in) {
- credits = get_u32(frm);
+ credits = p_get_u32(frm);
p_indent(level + 1, frm);
printf("credits %d\n", credits);
}
diff --git a/tools/parser/hidp.c b/tools/parser/hidp.c
index 6039eb9b..1adf8ed4 100644
--- a/tools/parser/hidp.c
+++ b/tools/parser/hidp.c
@@ -136,7 +136,7 @@ void hidp_dump(int level, struct frame *frm)
uint8_t hdr;
char *param;
- hdr = get_u8(frm);
+ hdr = p_get_u8(frm);
switch (hdr & 0xf0) {
case 0x00:
diff --git a/tools/parser/lmp.c b/tools/parser/lmp.c
index 3f65ace4..3d2772c2 100644
--- a/tools/parser/lmp.c
+++ b/tools/parser/lmp.c
@@ -34,9 +34,9 @@
#include "lib/hci.h"
#include "lib/hci_lib.h"
-#define LMP_U8(frm) (get_u8(frm))
-#define LMP_U16(frm) (btohs(htons(get_u16(frm))))
-#define LMP_U32(frm) (btohl(htonl(get_u32(frm))))
+#define LMP_U8(frm) (p_get_u8(frm))
+#define LMP_U16(frm) (btohs(htons(p_get_u16(frm))))
+#define LMP_U32(frm) (btohl(htonl(p_get_u32(frm))))
static enum {
IN_RAND,
diff --git a/tools/parser/obex.c b/tools/parser/obex.c
index 66b7eff9..0612c30d 100644
--- a/tools/parser/obex.c
+++ b/tools/parser/obex.c
@@ -200,7 +200,7 @@ static void parse_headers(int level, struct frame *frm)
uint32_t hv32;
while (frm->len > 0) {
- hi = get_u8(frm);
+ hi = p_get_u8(frm);
p_indent(level, frm);
@@ -212,7 +212,7 @@ static void parse_headers(int level, struct frame *frm)
return;
}
- len = get_u16(frm) - 3;
+ len = p_get_u16(frm) - 3;
printf(" = Unicode length %d\n", len);
if (frm->len < len)
@@ -229,7 +229,7 @@ static void parse_headers(int level, struct frame *frm)
return;
}
- len = get_u16(frm) - 3;
+ len = p_get_u16(frm) - 3;
printf(" = Sequence length %d\n", len);
if (frm->len < len)
@@ -246,7 +246,7 @@ static void parse_headers(int level, struct frame *frm)
return;
}
- hv8 = get_u8(frm);
+ hv8 = p_get_u8(frm);
printf(" = %d\n", hv8);
break;
@@ -256,7 +256,7 @@ static void parse_headers(int level, struct frame *frm)
return;
}
- hv32 = get_u32(frm);
+ hv32 = p_get_u32(frm);
printf(" = %u\n", hv32);
break;
}
@@ -272,8 +272,8 @@ void obex_dump(int level, struct frame *frm)
frm = add_frame(frm);
while (frm->len > 2) {
- opcode = get_u8(frm);
- length = get_u16(frm);
+ opcode = p_get_u8(frm);
+ length = p_get_u16(frm);
status = opcode & 0x7f;
if ((int) frm->len < length - 3) {
@@ -316,9 +316,9 @@ void obex_dump(int level, struct frame *frm)
return;
}
- version = get_u8(frm);
- flags = get_u8(frm);
- pktlen = get_u16(frm);
+ version = p_get_u8(frm);
+ flags = p_get_u8(frm);
+ pktlen = p_get_u16(frm);
printf(" version %d.%d flags %d mtu %d\n",
version >> 4, version & 0xf, flags, pktlen);
break;
@@ -329,8 +329,8 @@ void obex_dump(int level, struct frame *frm)
return;
}
- flags = get_u8(frm);
- constants = get_u8(frm);
+ flags = p_get_u8(frm);
+ constants = p_get_u8(frm);
printf(" flags %d constants %d\n", flags, constants);
break;
diff --git a/tools/parser/parser.h b/tools/parser/parser.h
index 62b8ac51..b7e1d756 100644
--- a/tools/parser/parser.h
+++ b/tools/parser/parser.h
@@ -161,7 +161,7 @@ static inline void p_ba2str(const bdaddr_t *ba, char *str)
/* get_uXX functions do byte swaping */
-static inline uint8_t get_u8(struct frame *frm)
+static inline uint8_t p_get_u8(struct frame *frm)
{
uint8_t *u8_ptr = frm->ptr;
frm->ptr += 1;
@@ -169,7 +169,7 @@ static inline uint8_t get_u8(struct frame *frm)
return *u8_ptr;
}
-static inline uint16_t get_u16(struct frame *frm)
+static inline uint16_t p_get_u16(struct frame *frm)
{
uint16_t *u16_ptr = frm->ptr;
frm->ptr += 2;
@@ -177,7 +177,7 @@ static inline uint16_t get_u16(struct frame *frm)
return get_be16(u16_ptr);
}
-static inline uint32_t get_u32(struct frame *frm)
+static inline uint32_t p_get_u32(struct frame *frm)
{
uint32_t *u32_ptr = frm->ptr;
frm->ptr += 4;
@@ -185,7 +185,7 @@ static inline uint32_t get_u32(struct frame *frm)
return get_be32(u32_ptr);
}
-static inline uint64_t get_u64(struct frame *frm)
+static inline uint64_t p_get_u64(struct frame *frm)
{
uint64_t *u64_ptr = frm->ptr;
uint64_t u64 = get_unaligned(u64_ptr), tmp;
@@ -196,10 +196,10 @@ static inline uint64_t get_u64(struct frame *frm)
return u64;
}
-static inline void get_u128(struct frame *frm, uint64_t *l, uint64_t *h)
+static inline void p_get_u128(struct frame *frm, uint64_t *l, uint64_t *h)
{
- *h = get_u64(frm);
- *l = get_u64(frm);
+ *h = p_get_u64(frm);
+ *l = p_get_u64(frm);
}
char *get_uuid_name(int uuid);
diff --git a/tools/parser/ppp.c b/tools/parser/ppp.c
index 256e1723..3847ff3a 100644
--- a/tools/parser/ppp.c
+++ b/tools/parser/ppp.c
@@ -99,8 +99,8 @@ static inline char *proto2str(uint16_t proto)
static void hdlc_dump(int level, struct frame *frm)
{
- uint8_t addr = get_u8(frm);
- uint8_t ctrl = get_u8(frm);
+ uint8_t addr = p_get_u8(frm);
+ uint8_t ctrl = p_get_u8(frm);
uint16_t fcs, proto;
fcs = get_unaligned((uint16_t *) (frm->ptr + frm->len - 2));
@@ -118,9 +118,9 @@ static void hdlc_dump(int level, struct frame *frm)
dir2str(frm->in), addr, ctrl, frm->len, fcs);
if (*((uint8_t *) frm->ptr) & 0x80)
- proto = get_u16(frm);
+ proto = p_get_u16(frm);
else
- proto = get_u8(frm);
+ proto = p_get_u8(frm);
p_indent(level + 1, frm);
printf("PPP: %s (0x%04x): len %d\n", proto2str(proto), proto, frm->len);
diff --git a/tools/parser/sap.c b/tools/parser/sap.c
index 0c87c36e..f51f0cc3 100644
--- a/tools/parser/sap.c
+++ b/tools/parser/sap.c
@@ -273,35 +273,35 @@ static void parse_parameters(int level, struct frame *frm)
while (frm->len > 3) {
p_indent(level, frm);
- param = get_u8(frm);
- get_u8(frm);
- len = get_u16(frm);
+ param = p_get_u8(frm);
+ p_get_u8(frm);
+ len = p_get_u16(frm);
printf("%s (0x%02x) len %d = ", param2str(param), param, len);
switch (param) {
case SAP_PARAM_ID_MAX_MSG_SIZE:
- printf("%d\n", get_u16(frm));
+ printf("%d\n", p_get_u16(frm));
break;
case SAP_PARAM_ID_CONN_STATUS:
- pv8 = get_u8(frm);
+ pv8 = p_get_u8(frm);
printf("0x%02x (%s)\n", pv8, status2str(pv8));
break;
case SAP_PARAM_ID_RESULT_CODE:
case SAP_PARAM_ID_CARD_READER_STATUS:
- pv8 = get_u8(frm);
+ pv8 = p_get_u8(frm);
printf("0x%02x (%s)\n", pv8, result2str(pv8));
break;
case SAP_PARAM_ID_DISCONNECT_IND:
- pv8 = get_u8(frm);
+ pv8 = p_get_u8(frm);
printf("0x%02x (%s)\n", pv8, disctype2str(pv8));
break;
case SAP_PARAM_ID_STATUS_CHANGE:
- pv8 = get_u8(frm);
+ pv8 = p_get_u8(frm);
printf("0x%02x (%s)\n", pv8, statuschg2str(pv8));
break;
case SAP_PARAM_ID_TRANSPORT_PROTOCOL:
- pv8 = get_u8(frm);
+ pv8 = p_get_u8(frm);
printf("0x%02x (%s)\n", pv8, prot2str(pv8));
break;
default:
@@ -321,11 +321,11 @@ void sap_dump(int level, struct frame *frm)
{
uint8_t msg, params;
- msg = get_u8(frm);
- params = get_u8(frm);
+ msg = p_get_u8(frm);
+ params = p_get_u8(frm);
/* Skip reserved field */
- get_u16(frm);
+ p_get_u16(frm);
p_indent(level, frm);
diff --git a/tools/parser/sdp.c b/tools/parser/sdp.c
index 0e283281..dba9a365 100644
--- a/tools/parser/sdp.c
+++ b/tools/parser/sdp.c
@@ -240,7 +240,7 @@ static inline char* get_attr_id_name(int attr_id)
static inline uint8_t parse_de_hdr(struct frame *frm, int *n)
{
- uint8_t de_hdr = get_u8(frm);
+ uint8_t de_hdr = p_get_u8(frm);
uint8_t de_type = de_hdr >> 3;
uint8_t siz_idx = de_hdr & 0x07;
@@ -248,13 +248,13 @@ static inline uint8_t parse_de_hdr(struct frame *frm, int *n)
if (sdp_siz_idx_lookup_table[siz_idx].addl_bits) {
switch(sdp_siz_idx_lookup_table[siz_idx].num_bytes) {
case 1:
- *n = get_u8(frm); break;
+ *n = p_get_u8(frm); break;
case 2:
- *n = get_u16(frm); break;
+ *n = p_get_u16(frm); break;
case 4:
- *n = get_u32(frm); break;
+ *n = p_get_u32(frm); break;
case 8:
- *n = get_u64(frm); break;
+ *n = p_get_u64(frm); break;
}
} else
*n = sdp_siz_idx_lookup_table[siz_idx].num_bytes;
@@ -280,25 +280,25 @@ static inline void print_int(uint8_t de_type, int level, int n, struct frame *fr
switch(n) {
case 1: /* 8-bit */
- val = get_u8(frm);
+ val = p_get_u8(frm);
if (channel && de_type == SDP_DE_UINT)
if (*channel == 0)
*channel = val;
break;
case 2: /* 16-bit */
- val = get_u16(frm);
+ val = p_get_u16(frm);
if (psm && de_type == SDP_DE_UINT)
if (*psm == 0)
*psm = val;
break;
case 4: /* 32-bit */
- val = get_u32(frm);
+ val = p_get_u32(frm);
break;
case 8: /* 64-bit */
- val = get_u64(frm);
+ val = p_get_u64(frm);
break;
case 16:/* 128-bit */
- get_u128(frm, &val, &val2);
+ p_get_u128(frm, &val, &val2);
printf(" 0x%jx", val2);
if (val < 0x1000000000000000LL)
printf("0");
@@ -322,11 +322,11 @@ static inline void print_uuid(int n, struct frame *frm, uint16_t *psm, uint8_t *
switch(n) {
case 2: /* 16-bit UUID */
- uuid = get_u16(frm);
+ uuid = p_get_u16(frm);
s = "uuid-16";
break;
case 4: /* 32_bit UUID */
- uuid = get_u32(frm);
+ uuid = p_get_u32(frm);
s = "uuid-32";
break;
case 16: /* 128-bit UUID */
@@ -483,14 +483,14 @@ static inline void print_attr_id_list(int level, struct frame *frm)
char *name;
switch(n2) {
case 2:
- attr_id = get_u16(frm);
+ attr_id = p_get_u16(frm);
name = get_attr_id_name(attr_id);
if (!name)
name = "unknown";
printf(" 0x%04x (%s)", attr_id, name);
break;
case 4:
- attr_id_range = get_u32(frm);
+ attr_id_range = p_get_u32(frm);
printf(" 0x%04x - 0x%04x",
(attr_id_range >> 16),
(attr_id_range & 0xFFFF));
@@ -520,7 +520,7 @@ static inline void print_attr_list(int level, struct frame *frm)
/* Print AttributeID */
if (parse_de_hdr(frm, &n2) == SDP_DE_UINT && n2 == sizeof(attr_id)) {
char *name;
- attr_id = get_u16(frm);
+ attr_id = p_get_u16(frm);
p_indent(level, 0);
name = get_attr_id_name(attr_id);
if (!name)
@@ -685,7 +685,7 @@ void sdp_dump(int level, struct frame *frm)
switch (hdr->pid) {
case SDP_ERROR_RSP:
p_indent(level + 1, frm);
- printf("code 0x%x info ", get_u16(frm));
+ printf("code 0x%x info ", p_get_u16(frm));
if (frm->len > 0)
hex_dump(0, frm, frm->len);
else
@@ -698,7 +698,7 @@ void sdp_dump(int level, struct frame *frm)
/* Parse MaximumServiceRecordCount */
p_indent(level + 1, frm);
- printf("max %d\n", get_u16(frm));
+ printf("max %d\n", p_get_u16(frm));
/* Parse ContinuationState */
print_cont_state(level + 1, frm->ptr);
@@ -706,10 +706,10 @@ void sdp_dump(int level, struct frame *frm)
case SDP_SERVICE_SEARCH_RSP:
/* Parse TotalServiceRecordCount */
- total = get_u16(frm);
+ total = p_get_u16(frm);
/* Parse CurrentServiceRecordCount */
- count = get_u16(frm);
+ count = p_get_u16(frm);
p_indent(level + 1, frm);
if (count < total)
printf("count %d of %d\n", count, total);
@@ -722,7 +722,7 @@ void sdp_dump(int level, struct frame *frm)
p_indent(level + 1, frm);
printf("handle%s", count > 1 ? "s" : "");
for (i = 0; i < count; i++)
- printf(" 0x%x", get_u32(frm));
+ printf(" 0x%x", p_get_u32(frm));
printf("\n");
}
@@ -733,11 +733,11 @@ void sdp_dump(int level, struct frame *frm)
case SDP_SERVICE_ATTR_REQ:
/* Parse ServiceRecordHandle */
p_indent(level + 1, frm);
- printf("handle 0x%x\n", get_u32(frm));
+ printf("handle 0x%x\n", p_get_u32(frm));
/* Parse MaximumAttributeByteCount */
p_indent(level + 1, frm);
- printf("max %d\n", get_u16(frm));
+ printf("max %d\n", p_get_u16(frm));
/* Parse ServiceSearchPattern */
print_attr_id_list(level + 1, frm);
@@ -748,7 +748,7 @@ void sdp_dump(int level, struct frame *frm)
case SDP_SERVICE_ATTR_RSP:
/* Parse AttributeByteCount */
- count = get_u16(frm);
+ count = p_get_u16(frm);
p_indent(level + 1, frm);
printf("count %d\n", count);
@@ -770,7 +770,7 @@ void sdp_dump(int level, struct frame *frm)
/* Parse MaximumAttributeByteCount */
p_indent(level + 1, frm);
- printf("max %d\n", get_u16(frm));
+ printf("max %d\n", p_get_u16(frm));
/* Parse AttributeList */
print_attr_id_list(level + 1, frm);
@@ -781,7 +781,7 @@ void sdp_dump(int level, struct frame *frm)
case SDP_SERVICE_SEARCH_ATTR_RSP:
/* Parse AttributeByteCount */
- count = get_u16(frm);
+ count = p_get_u16(frm);
p_indent(level + 1, frm);
printf("count %d\n", count);
diff --git a/tools/parser/smp.c b/tools/parser/smp.c
index c81b585e..97f02faa 100644
--- a/tools/parser/smp.c
+++ b/tools/parser/smp.c
@@ -151,12 +151,12 @@ static const char *smpreason2str(uint8_t reason)
static void smp_cmd_pairing_dump(int level, struct frame *frm)
{
- uint8_t cap = get_u8(frm);
- uint8_t oob = get_u8(frm);
- uint8_t auth = get_u8(frm);
- uint8_t key_size = get_u8(frm);
- uint8_t int_dist = get_u8(frm);
- uint8_t resp_dist = get_u8(frm);
+ uint8_t cap = p_get_u8(frm);
+ uint8_t oob = p_get_u8(frm);
+ uint8_t auth = p_get_u8(frm);
+ uint8_t key_size = p_get_u8(frm);
+ uint8_t int_dist = p_get_u8(frm);
+ uint8_t resp_dist = p_get_u8(frm);
p_indent(level, frm);
printf("capability 0x%2.2x oob 0x%2.2x auth req 0x%2.2x\n", cap, oob,
@@ -196,7 +196,7 @@ static void smp_cmd_pairing_confirm_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("key ");
for (i = 0; i < 16; i++)
- printf("%2.2x", get_u8(frm));
+ printf("%2.2x", p_get_u8(frm));
printf("\n");
}
@@ -207,13 +207,13 @@ static void smp_cmd_pairing_random_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("random ");
for (i = 0; i < 16; i++)
- printf("%2.2x", get_u8(frm));
+ printf("%2.2x", p_get_u8(frm));
printf("\n");
}
static void smp_cmd_pairing_failed_dump(int level, struct frame *frm)
{
- uint8_t reason = get_u8(frm);
+ uint8_t reason = p_get_u8(frm);
p_indent(level, frm);
printf("reason 0x%2.2x\n", reason);
@@ -229,13 +229,13 @@ static void smp_cmd_encrypt_info_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("LTK ");
for (i = 0; i < 16; i++)
- printf("%2.2x", get_u8(frm));
+ printf("%2.2x", p_get_u8(frm));
printf("\n");
}
static void smp_cmd_master_ident_dump(int level, struct frame *frm)
{
- uint16_t ediv = btohs(htons(get_u16(frm)));
+ uint16_t ediv = btohs(htons(p_get_u16(frm)));
int i;
p_indent(level, frm);
@@ -243,7 +243,7 @@ static void smp_cmd_master_ident_dump(int level, struct frame *frm)
printf("Rand 0x");
for (i = 0; i < 8; i++)
- printf("%2.2x", get_u8(frm));
+ printf("%2.2x", p_get_u8(frm));
printf("\n");
}
@@ -254,13 +254,13 @@ static void smp_cmd_ident_info_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("IRK ");
for (i = 0; i < 16; i++)
- printf("%2.2x", get_u8(frm));
+ printf("%2.2x", p_get_u8(frm));
printf("\n");
}
static void smp_cmd_ident_addr_info_dump(int level, struct frame *frm)
{
- uint8_t type = get_u8(frm);
+ uint8_t type = p_get_u8(frm);
char addr[18];
p_indent(level, frm);
@@ -275,13 +275,13 @@ static void smp_cmd_sign_info_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("CSRK ");
for (i = 0; i < 16; i++)
- printf("%2.2x", get_u8(frm));
+ printf("%2.2x", p_get_u8(frm));
printf("\n");
}
static void smp_cmd_security_req_dump(int level, struct frame *frm)
{
- uint8_t auth = get_u8(frm);
+ uint8_t auth = p_get_u8(frm);
p_indent(level, frm);
printf("auth req 0x%2.2x\n", auth);
@@ -291,7 +291,7 @@ void smp_dump(int level, struct frame *frm)
{
uint8_t cmd;
- cmd = get_u8(frm);
+ cmd = p_get_u8(frm);
p_indent(level, frm);
printf("SMP: %s (0x%.2x)\n", smpcmd2str(cmd), cmd);
diff --git a/tools/rctest.c b/tools/rctest.c
index bdc1eb56..6d84e075 100644
--- a/tools/rctest.c
+++ b/tools/rctest.c
@@ -80,8 +80,8 @@ static bdaddr_t auto_bdaddr;
static uint16_t uuid = 0x0000;
static uint8_t channel = 10;
-static char *filename = NULL;
-static char *savefile = NULL;
+static const char *filename = NULL;
+static const char *savefile = NULL;
static int save_fd = -1;
static int master = 0;
@@ -102,7 +102,7 @@ static float tv2fl(struct timeval tv)
static uint8_t get_channel(const char *svr, uint16_t uuid)
{
sdp_session_t *sdp;
- sdp_list_t *srch, *attrs, *rsp;
+ sdp_list_t *srch, *attrs, *rsp, *protos;
uuid_t svclass;
uint16_t attr;
bdaddr_t dst;
@@ -128,7 +128,6 @@ static uint8_t get_channel(const char *svr, uint16_t uuid)
for (; rsp; rsp = rsp->next) {
sdp_record_t *rec = (sdp_record_t *) rsp->data;
- sdp_list_t *protos;
if (!sdp_get_access_protos(rec, &protos)) {
channel = sdp_get_proto_port(protos, RFCOMM_UUID);
@@ -137,7 +136,11 @@ static uint8_t get_channel(const char *svr, uint16_t uuid)
}
}
+ sdp_list_free(protos, NULL);
+
done:
+ sdp_list_free(srch, NULL);
+ sdp_list_free(attrs, NULL);
sdp_close(sdp);
return channel;
@@ -559,6 +562,7 @@ static void do_send(int sk)
}
len = read(fd, buf, data_size);
send(sk, buf, len, 0);
+ close(fd);
return;
} else {
for (i = 6; i < data_size; i++)
@@ -592,6 +596,7 @@ static void send_mode(int sk)
syslog(LOG_INFO, "Close failed: %m");
else
syslog(LOG_INFO, "Done");
+ close(sk);
}
static void reconnect_mode(char *svr)
@@ -798,11 +803,11 @@ int main(int argc, char *argv[])
break;
case 'B':
- filename = strdup(optarg);
+ filename = optarg;
break;
case 'O':
- savefile = strdup(optarg);
+ savefile = optarg;
break;
case 'N':
diff --git a/tools/rfcomm-tester.c b/tools/rfcomm-tester.c
index 55b6ac63..b20d70d5 100644
--- a/tools/rfcomm-tester.c
+++ b/tools/rfcomm-tester.c
@@ -34,8 +34,8 @@
#include <glib.h>
#include "lib/bluetooth.h"
+#include "lib/rfcomm.h"
#include "lib/mgmt.h"
-#include "bluetooth/rfcomm.h"
#include "monitor/bt.h"
#include "emulator/bthost.h"
diff --git a/tools/sco-tester.c b/tools/sco-tester.c
index d55d51a3..651fbe01 100644
--- a/tools/sco-tester.c
+++ b/tools/sco-tester.c
@@ -160,6 +160,7 @@ static void read_index_list_callback(uint8_t status, uint16_t length,
if (!data->hciemu) {
tester_warn("Failed to setup HCI emulation");
tester_pre_setup_failed();
+ return;
}
tester_print("New hciemu instance created");
diff --git a/tools/sdptool.c b/tools/sdptool.c
index 891d3883..cc67ea7d 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -921,9 +921,14 @@ static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attri
}
/* Create arrays */
- dtdArray = (void **)malloc(argc * sizeof(void *));
- valueArray = (void **)malloc(argc * sizeof(void *));
- allocArray = (void **)malloc(argc * sizeof(void *));
+ dtdArray = malloc(argc * sizeof(void *));
+ valueArray = malloc(argc * sizeof(void *));
+ allocArray = malloc(argc * sizeof(void *));
+
+ if (!dtdArray || !valueArray || !allocArray) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
/* Loop on all args, add them in arrays */
for (i = 0; i < argc; i++) {
@@ -931,7 +936,12 @@ static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attri
if (!strncasecmp(argv[i], "u0x", 3)) {
/* UUID16 */
uint16_t value_int = strtoul((argv[i]) + 3, NULL, 16);
- uuid_t *value_uuid = (uuid_t *) malloc(sizeof(uuid_t));
+ uuid_t *value_uuid = malloc(sizeof(uuid_t));
+ if (!value_uuid) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
allocArray[i] = value_uuid;
sdp_uuid16_create(value_uuid, value_int);
@@ -940,7 +950,12 @@ static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attri
valueArray[i] = &value_uuid->value.uuid16;
} else if (!strncasecmp(argv[i], "0x", 2)) {
/* Int */
- uint32_t *value_int = (uint32_t *) malloc(sizeof(int));
+ uint32_t *value_int = malloc(sizeof(int));
+ if (!value_int) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
allocArray[i] = value_int;
*value_int = strtoul((argv[i]) + 2, NULL, 16);
@@ -967,9 +982,14 @@ static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attri
} else
printf("Failed to create pSequenceHolder\n");
+cleanup:
+ if (ret == -ENOMEM)
+ printf("Memory allocation failed\n");
+
/* Cleanup */
for (i = 0; i < argc; i++)
- free(allocArray[i]);
+ if (allocArray)
+ free(allocArray[i]);
free(dtdArray);
free(valueArray);
@@ -3296,6 +3316,7 @@ static int add_palmos(sdp_session_t *session, svc_info_t *si)
sdp_record_t record;
sdp_list_t *root, *svclass;
uuid_t root_uuid, svclass_uuid;
+ int err;
memset(&record, 0, sizeof(record));
record.handle = si->handle;
@@ -3308,7 +3329,12 @@ static int add_palmos(sdp_session_t *session, svc_info_t *si)
svclass = sdp_list_append(NULL, &svclass_uuid);
sdp_set_service_classes(&record, svclass);
- if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ err = sdp_device_record_register(session, &interface, &record,
+ SDP_RECORD_PERSIST);
+ sdp_list_free(root, NULL);
+ sdp_list_free(svclass, NULL);
+
+ if (err < 0) {
printf("Service Record registration failed\n");
return -1;
}
diff --git a/tools/smp-tester.c b/tools/smp-tester.c
index ab77b24e..d24c9b2b 100644
--- a/tools/smp-tester.c
+++ b/tools/smp-tester.c
@@ -326,13 +326,6 @@ static const struct smp_data smp_server_nval_req_3_test = {
.req_count = G_N_ELEMENTS(srv_nval_req_2),
};
-static const uint8_t smp_nval_req_4[] = { 0xff, 0xff };
-static const uint8_t smp_nval_req_4_rsp[] = { 0x05, 0x07 };
-
-static const struct smp_req_rsp srv_nval_req_3[] = {
- { smp_nval_req_4, sizeof(smp_nval_req_4), NULL, 0 },
-};
-
static const uint8_t smp_basic_req_1[] = { 0x01, /* Pairing Request */
0x03, /* NoInputNoOutput */
0x00, /* OOB Flag */
@@ -455,8 +448,6 @@ static const uint8_t smp_sc_rsp_1[] = { 0x02, /* Pairing Response */
static const uint8_t smp_sc_pk[65] = { 0x0c };
-static const uint8_t smp_sc_failed_rsp_1[] = { 0x05, 0x08 };
-
static const struct smp_req_rsp cli_sc_req_2[] = {
{ NULL, 0, smp_sc_req_1, sizeof(smp_sc_req_1) },
{ smp_sc_rsp_1, sizeof(smp_sc_rsp_1), smp_sc_pk, sizeof(smp_sc_pk) },
@@ -502,7 +493,7 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
bthost = hciemu_client_get_host(data->hciemu);
bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
- bthost_set_adv_enable(bthost, 0x01, 0x00);
+ bthost_set_adv_enable(bthost, 0x01);
}
static void make_pk(struct test_data *data)
diff --git a/tools/test-runner.c b/tools/test-runner.c
new file mode 100644
index 00000000..42c2c1a4
--- /dev/null
+++ b/tools/test-runner.c
@@ -0,0 +1,869 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <poll.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "tools/hciattach.h"
+
+#ifndef WAIT_ANY
+#define WAIT_ANY (-1)
+#endif
+
+#define CMDLINE_MAX 2048
+
+static const char *own_binary;
+static char **test_argv;
+static int test_argc;
+
+static bool run_auto = false;
+static bool start_dbus = false;
+static int num_devs = 0;
+static const char *qemu_binary = NULL;
+static const char *kernel_image = NULL;
+
+static const char *qemu_table[] = {
+ "qemu-system-x86_64",
+ "qemu-system-i386",
+ "/usr/bin/qemu-system-x86_64",
+ "/usr/bin/qemu-system-i386",
+ NULL
+};
+
+static const char *find_qemu(void)
+{
+ int i;
+
+ for (i = 0; qemu_table[i]; i++) {
+ struct stat st;
+
+ if (!stat(qemu_table[i], &st))
+ return qemu_table[i];
+ }
+
+ return NULL;
+}
+
+static const char *kernel_table[] = {
+ "bzImage",
+ "arch/x86/boot/bzImage",
+ "vmlinux",
+ "arch/x86/boot/vmlinux",
+ NULL
+};
+
+static const char *find_kernel(void)
+{
+ int i;
+
+ for (i = 0; kernel_table[i]; i++) {
+ struct stat st;
+
+ if (!stat(kernel_table[i], &st))
+ return kernel_table[i];
+ }
+
+ return NULL;
+}
+
+static const struct {
+ const char *target;
+ const char *linkpath;
+} dev_table[] = {
+ { "/proc/self/fd", "/dev/fd" },
+ { "/proc/self/fd/0", "/dev/stdin" },
+ { "/proc/self/fd/1", "/dev/stdout" },
+ { "/proc/self/fd/2", "/dev/stderr" },
+ { }
+};
+
+static const struct {
+ const char *fstype;
+ const char *target;
+ const char *options;
+ unsigned long flags;
+} mount_table[] = {
+ { "sysfs", "/sys", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
+ { "proc", "/proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
+ { "devtmpfs", "/dev", "mode=0755", MS_NOSUID|MS_STRICTATIME },
+ { "devpts", "/dev/pts", "mode=0620", MS_NOSUID|MS_NOEXEC },
+ { "tmpfs", "/dev/shm", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME },
+ { "tmpfs", "/run", "mode=0755", MS_NOSUID|MS_NODEV|MS_STRICTATIME },
+ { "tmpfs", "/tmp", NULL, 0 },
+ { "debugfs", "/sys/kernel/debug", NULL, 0 },
+ { }
+};
+
+static const char *config_table[] = {
+ "/var/lib/bluetooth",
+ "/etc/bluetooth",
+ "/etc/dbus-1",
+ "/usr/share/dbus-1",
+ NULL
+};
+
+static void prepare_sandbox(void)
+{
+ int i;
+
+ for (i = 0; mount_table[i].fstype; i++) {
+ struct stat st;
+
+ if (lstat(mount_table[i].target, &st) < 0) {
+ printf("Creating %s\n", mount_table[i].target);
+ mkdir(mount_table[i].target, 0755);
+ }
+
+ printf("Mounting %s to %s\n", mount_table[i].fstype,
+ mount_table[i].target);
+
+ if (mount(mount_table[i].fstype,
+ mount_table[i].target,
+ mount_table[i].fstype,
+ mount_table[i].flags,
+ mount_table[i].options) < 0)
+ perror("Failed to mount filesystem");
+ }
+
+ for (i = 0; dev_table[i].target; i++) {
+ printf("Linking %s to %s\n", dev_table[i].linkpath,
+ dev_table[i].target);
+
+ if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
+ perror("Failed to create device symlink");
+ }
+
+ printf("Creating new session group leader\n");
+ setsid();
+
+ printf("Setting controlling terminal\n");
+ ioctl(STDIN_FILENO, TIOCSCTTY, 1);
+
+ for (i = 0; config_table[i]; i++) {
+ printf("Creating %s\n", config_table[i]);
+
+ if (mount("tmpfs", config_table[i], "tmpfs",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+ "mode=0755") < 0)
+ perror("Failed to create filesystem");
+ }
+}
+
+static char *const qemu_argv[] = {
+ "",
+ "-nodefaults",
+ "-nodefconfig",
+ "-no-user-config",
+ "-monitor", "none",
+ "-display", "none",
+ "-machine", "type=q35,accel=kvm:tcg",
+ "-m", "192M",
+ "-nographic",
+ "-vga", "none",
+ "-net", "none",
+ "-balloon", "none",
+ "-no-acpi",
+ "-no-hpet",
+ "-no-reboot",
+ "-fsdev", "local,id=fsdev-root,path=/,readonly,security_model=none",
+ "-device", "virtio-9p-pci,fsdev=fsdev-root,mount_tag=/dev/root",
+ "-chardev", "stdio,id=chardev-serial0,signal=off",
+ "-device", "pci-serial,chardev=chardev-serial0",
+ NULL
+};
+
+static char *const qemu_envp[] = {
+ "HOME=/",
+ NULL
+};
+
+static void check_virtualization(void)
+{
+#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
+ uint32_t ecx;
+
+ __asm__ __volatile__("cpuid" : "=c" (ecx) : "a" (1) : "memory");
+
+ if (!!(ecx & (1 << 5)))
+ printf("Found support for Virtual Machine eXtensions\n");
+#endif
+}
+
+static void start_qemu(void)
+{
+ char cwd[PATH_MAX], initcmd[PATH_MAX], testargs[PATH_MAX];
+ char cmdline[CMDLINE_MAX];
+ char **argv;
+ int i, pos;
+
+ check_virtualization();
+
+ if (!getcwd(cwd, sizeof(cwd)))
+ strcat(cwd, "/");
+
+ if (own_binary[0] == '/')
+ snprintf(initcmd, sizeof(initcmd), "%s", own_binary);
+ else
+ snprintf(initcmd, sizeof(initcmd), "%s/%s", cwd, own_binary);
+
+ pos = snprintf(testargs, sizeof(testargs), "%s", test_argv[0]);
+
+ for (i = 1; i < test_argc; i++) {
+ int len = sizeof(testargs) - pos;
+ pos += snprintf(testargs + pos, len, " %s", test_argv[i]);
+ }
+
+ snprintf(cmdline, sizeof(cmdline),
+ "console=ttyS0,115200n8 earlyprintk=serial "
+ "rootfstype=9p "
+ "rootflags=trans=virtio,version=9p2000.L "
+ "acpi=off pci=noacpi noapic quiet ro init=%s "
+ "TESTHOME=%s TESTDBUS=%u TESTDEVS=%d "
+ "TESTAUTO=%u TESTARGS=\'%s\'", initcmd, cwd,
+ start_dbus, num_devs, run_auto, testargs);
+
+ argv = alloca(sizeof(qemu_argv) +
+ (sizeof(char *) * (4 + (num_devs * 4))));
+ memcpy(argv, qemu_argv, sizeof(qemu_argv));
+
+ pos = (sizeof(qemu_argv) / sizeof(char *)) - 1;
+
+ argv[0] = (char *) qemu_binary;
+
+ argv[pos++] = "-kernel";
+ argv[pos++] = (char *) kernel_image;
+ argv[pos++] = "-append";
+ argv[pos++] = (char *) cmdline;
+
+ for (i = 0; i < num_devs; i++) {
+ const char *path = "/tmp/bt-server-bredr";
+ char *chrdev, *serdev;
+
+ chrdev = alloca(32 + strlen(path));
+ sprintf(chrdev, "socket,path=%s,id=bt%d", path, i);
+
+ serdev = alloca(32);
+ sprintf(serdev, "pci-serial,chardev=bt%d", i);
+
+ argv[pos++] = "-chardev";
+ argv[pos++] = chrdev;
+ argv[pos++] = "-device";
+ argv[pos++] = serdev;
+ }
+
+ argv[pos] = NULL;
+
+ execve(argv[0], argv, qemu_envp);
+}
+
+static int open_serial(const char *path)
+{
+ struct termios ti;
+ int fd, saved_ldisc, ldisc = N_HCI;
+
+ fd = open(path, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ perror("Failed to open serial port");
+ return -1;
+ }
+
+ if (tcflush(fd, TCIOFLUSH) < 0) {
+ perror("Failed to flush serial port");
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, TIOCGETD, &saved_ldisc) < 0) {
+ perror("Failed get serial line discipline");
+ close(fd);
+ return -1;
+ }
+
+ /* Switch TTY to raw mode */
+ memset(&ti, 0, sizeof(ti));
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= (B115200 | CLOCAL | CREAD);
+
+ /* Set flow control */
+ ti.c_cflag |= CRTSCTS;
+
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Failed to set serial port settings");
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
+ perror("Failed set serial line discipline");
+ close(fd);
+ return -1;
+ }
+
+ printf("Switched line discipline from %d to %d\n", saved_ldisc, ldisc);
+
+ return fd;
+}
+
+static int attach_proto(const char *path, unsigned int proto,
+ unsigned int mandatory_flags,
+ unsigned int optional_flags)
+{
+ unsigned int flags = mandatory_flags | optional_flags;
+ int fd, dev_id;
+
+ fd = open_serial(path);
+ if (fd < 0)
+ return -1;
+
+ if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
+ if (errno == EINVAL) {
+ if (ioctl(fd, HCIUARTSETFLAGS, mandatory_flags) < 0) {
+ perror("Failed to set mandatory flags");
+ close(fd);
+ return -1;
+ }
+ } else {
+ perror("Failed to set flags");
+ close(fd);
+ return -1;
+ }
+ }
+
+ if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
+ perror("Failed to set protocol");
+ close(fd);
+ return -1;
+ }
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE);
+ if (dev_id < 0) {
+ perror("Failed to get device id");
+ close(fd);
+ return -1;
+ }
+
+ printf("Device index %d attached\n", dev_id);
+
+ return fd;
+}
+
+static void create_dbus_system_conf(void)
+{
+ FILE *fp;
+
+ fp = fopen("/etc/dbus-1/system.conf", "we");
+ if (!fp)
+ return;
+
+ fputs("<!DOCTYPE busconfig PUBLIC "
+ "\"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\" "
+ "\"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n", fp);
+ fputs("<busconfig>\n", fp);
+ fputs("<type>system</type>\n", fp);
+ fputs("<listen>unix:path=/run/dbus/system_bus_socket</listen>\n", fp);
+ fputs("<policy context=\"default\">\n", fp);
+ fputs("<allow user=\"*\"/>\n", fp);
+ fputs("<allow own=\"*\"/>\n", fp);
+ fputs("<allow send_type=\"method_call\"/>\n",fp);
+ fputs("<allow send_type=\"signal\"/>\n", fp);
+ fputs("<allow send_type=\"method_return\"/>\n", fp);
+ fputs("<allow send_type=\"error\"/>\n", fp);
+ fputs("<allow receive_type=\"method_call\"/>\n",fp);
+ fputs("<allow receive_type=\"signal\"/>\n", fp);
+ fputs("<allow receive_type=\"method_return\"/>\n", fp);
+ fputs("<allow receive_type=\"error\"/>\n", fp);
+ fputs("</policy>\n", fp);
+ fputs("</busconfig>\n", fp);
+
+ fclose(fp);
+
+ mkdir("/run/dbus", 0755);
+}
+
+static pid_t start_dbus_daemon(void)
+{
+ char *argv[3], *envp[1];
+ pid_t pid;
+ int i;
+
+ argv[0] = "/usr/bin/dbus-daemon";
+ argv[1] = "--system";
+ argv[2] = NULL;
+
+ envp[0] = NULL;
+
+ printf("Starting D-Bus daemon\n");
+
+ pid = fork();
+ if (pid < 0) {
+ perror("Failed to fork new process");
+ return -1;
+ }
+
+ if (pid == 0) {
+ execve(argv[0], argv, envp);
+ exit(EXIT_SUCCESS);
+ }
+
+ printf("D-Bus daemon process %d created\n", pid);
+
+ for (i = 0; i < 20; i++) {
+ struct stat st;
+
+ if (!stat("/run/dbus/system_bus_socket", &st)) {
+ printf("Found D-Bus daemon socket\n");
+ break;
+ }
+
+ usleep(25 * 1000);
+ }
+
+ return pid;
+}
+
+static const char *daemon_table[] = {
+ "bluetoothd",
+ "src/bluetoothd",
+ "/usr/sbin/bluetoothd",
+ "/usr/libexec/bluetooth/bluetoothd",
+ NULL
+};
+
+static pid_t start_bluetooth_daemon(const char *home)
+{
+ const char *daemon = NULL;
+ char *argv[3], *envp[2];
+ pid_t pid;
+ int i;
+
+ if (chdir(home + 5) < 0) {
+ perror("Failed to change home directory for daemon");
+ return -1;
+ }
+
+ for (i = 0; daemon_table[i]; i++) {
+ struct stat st;
+
+ if (!stat(daemon_table[i], &st)) {
+ daemon = daemon_table[i];
+ break;
+ }
+ }
+
+ if (!daemon) {
+ fprintf(stderr, "Failed to locate Bluetooth daemon binary\n");
+ return -1;
+ }
+
+ printf("Using Bluetooth daemon %s\n", daemon);
+
+ argv[0] = (char *) daemon;
+ argv[1] = "--nodetach";
+ argv[2] = NULL;
+
+ envp[0] = "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket";
+ envp[1] = NULL;
+
+ printf("Starting Bluetooth daemon\n");
+
+ pid = fork();
+ if (pid < 0) {
+ perror("Failed to fork new process");
+ return -1;
+ }
+
+ if (pid == 0) {
+ execve(argv[0], argv, envp);
+ exit(EXIT_SUCCESS);
+ }
+
+ printf("Bluetooth daemon process %d created\n", pid);
+
+ return pid;
+}
+
+static const char *test_table[] = {
+ "mgmt-tester",
+ "smp-tester",
+ "l2cap-tester",
+ "rfcomm-tester",
+ "sco-tester",
+ "bnep-tester",
+ "check-selftest",
+ "tools/mgmt-tester",
+ "tools/smp-tester",
+ "tools/l2cap-tester",
+ "tools/rfcomm-tester",
+ "tools/sco-tester",
+ "tools/bnep-tester",
+ "tools/check-selftest",
+ NULL
+};
+
+static void run_command(char *cmdname, char *home)
+{
+ char *argv[9], *envp[3];
+ int pos = 0, idx = 0;
+ int serial_fd;
+ pid_t pid, dbus_pid, daemon_pid;
+
+ if (num_devs) {
+ const char *node = "/dev/ttyS1";
+ unsigned int basic_flags, extra_flags;
+
+ printf("Attaching BR/EDR controller to %s\n", node);
+
+ basic_flags = (1 << HCI_UART_RESET_ON_INIT);
+ extra_flags = (1 << HCI_UART_VND_DETECT);
+
+ serial_fd = attach_proto(node, HCI_UART_H4, basic_flags,
+ extra_flags);
+ } else
+ serial_fd = -1;
+
+ if (start_dbus) {
+ create_dbus_system_conf();
+ dbus_pid = start_dbus_daemon();
+ daemon_pid = start_bluetooth_daemon(home);
+ } else {
+ dbus_pid = -1;
+ daemon_pid = -1;
+ }
+
+start_next:
+ if (run_auto) {
+ if (chdir(home + 5) < 0) {
+ perror("Failed to change home test directory");
+ return;
+ }
+
+ while (1) {
+ struct stat st;
+
+ if (!test_table[idx])
+ return;
+
+ if (!stat(test_table[idx], &st))
+ break;
+
+ idx++;
+ }
+
+ argv[0] = (char *) test_table[idx];
+ argv[1] = "-q";
+ argv[2] = NULL;
+ } else {
+ while (1) {
+ char *ptr;
+
+ ptr = strchr(cmdname, ' ');
+ if (!ptr) {
+ argv[pos++] = cmdname;
+ break;
+ }
+
+ *ptr = '\0';
+ argv[pos++] = cmdname;
+ if (pos > 8)
+ break;
+
+ cmdname = ptr + 1;
+ }
+
+ argv[pos] = NULL;
+ }
+
+ pos = 0;
+ envp[pos++] = "TERM=linux";
+ if (home)
+ envp[pos++] = home;
+ envp[pos] = NULL;
+
+ printf("Running command %s\n", argv[0]);
+
+ pid = fork();
+ if (pid < 0) {
+ perror("Failed to fork new process");
+ return;
+ }
+
+ if (pid == 0) {
+ if (home) {
+ printf("Changing into directory %s\n", home + 5);
+ if (chdir(home + 5) < 0)
+ perror("Failed to change directory");
+ }
+
+ execve(argv[0], argv, envp);
+ exit(EXIT_SUCCESS);
+ }
+
+ printf("New process %d created\n", pid);
+
+ while (1) {
+ pid_t corpse;
+ int status;
+
+ corpse = waitpid(WAIT_ANY, &status, 0);
+ if (corpse < 0 || corpse == 0)
+ continue;
+
+ if (WIFEXITED(status))
+ printf("Process %d exited with status %d\n",
+ corpse, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ printf("Process %d terminated with signal %d\n",
+ corpse, WTERMSIG(status));
+ else if (WIFSTOPPED(status))
+ printf("Process %d stopped with signal %d\n",
+ corpse, WSTOPSIG(status));
+ else if (WIFCONTINUED(status))
+ printf("Process %d continued\n", corpse);
+
+ if (corpse == dbus_pid) {
+ printf("D-Bus daemon terminated\n");
+ dbus_pid = -1;
+ }
+
+ if (corpse == daemon_pid) {
+ printf("Bluetooth daemon terminated\n");
+ daemon_pid = -1;
+ }
+
+ if (corpse == pid) {
+ if (!run_auto) {
+ if (daemon_pid > 0)
+ kill(daemon_pid, SIGTERM);
+ if (dbus_pid > 0)
+ kill(dbus_pid, SIGTERM);
+ }
+ break;
+ }
+ }
+
+ if (run_auto) {
+ idx++;
+ goto start_next;
+ }
+
+ if (serial_fd >= 0) {
+ close(serial_fd);
+ serial_fd = -1;
+ }
+}
+
+static void run_tests(void)
+{
+ char cmdline[CMDLINE_MAX], *ptr, *cmds, *home = NULL;
+ FILE *fp;
+
+ fp = fopen("/proc/cmdline", "re");
+ if (!fp) {
+ fprintf(stderr, "Failed to open kernel command line\n");
+ return;
+ }
+
+ ptr = fgets(cmdline, sizeof(cmdline), fp);
+ fclose(fp);
+
+ if (!ptr) {
+ fprintf(stderr, "Failed to read kernel command line\n");
+ return;
+ }
+
+ ptr = strstr(cmdline, "TESTARGS=");
+ if (!ptr) {
+ fprintf(stderr, "No test command section found\n");
+ return;
+ }
+
+ cmds = ptr + 10;
+ ptr = strchr(cmds, '\'');
+ if (!ptr) {
+ fprintf(stderr, "Malformed test command section\n");
+ return;
+ }
+
+ *ptr = '\0';
+
+ ptr = strstr(cmdline, "TESTAUTO=1");
+ if (ptr) {
+ printf("Automatic test execution requested\n");
+ run_auto= true;
+ }
+
+ ptr = strstr(cmdline, "TESTDEVS=1");
+ if (ptr) {
+ printf("Attachment of devices requested\n");
+ num_devs = 1;
+ }
+
+ ptr = strstr(cmdline, "TESTDBUS=1");
+ if (ptr) {
+ printf("D-Bus daemon requested\n");
+ start_dbus = true;
+ }
+
+ ptr = strstr(cmdline, "TESTHOME=");
+ if (ptr) {
+ home = ptr + 4;
+ ptr = strpbrk(home + 9, " \r\n");
+ if (ptr)
+ *ptr = '\0';
+ }
+
+ run_command(cmds, home);
+}
+
+static void usage(void)
+{
+ printf("test-runner - Automated test execution utility\n"
+ "Usage:\n");
+ printf("\ttest-runner [options] [--] <command> [args]\n");
+ printf("Options:\n"
+ "\t-a, --auto Find tests and run them\n"
+ "\t-d, --dbus Start D-Bus daemon\n"
+ "\t-u, --unix [path] Provide serial device\n"
+ "\t-q, --qemu <path> QEMU binary\n"
+ "\t-k, --kernel <image> Kernel image (bzImage)\n"
+ "\t-h, --help Show help options\n");
+}
+
+static const struct option main_options[] = {
+ { "all", no_argument, NULL, 'a' },
+ { "auto", no_argument, NULL, 'a' },
+ { "unix", no_argument, NULL, 'u' },
+ { "dbus", no_argument, NULL, 'd' },
+ { "qemu", required_argument, NULL, 'q' },
+ { "kernel", required_argument, NULL, 'k' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
+int main(int argc, char *argv[])
+{
+ if (getpid() == 1 && getppid() == 0) {
+ prepare_sandbox();
+ run_tests();
+
+ sync();
+ reboot(RB_AUTOBOOT);
+ return EXIT_SUCCESS;
+ }
+
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "audq:k:vh", main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'a':
+ run_auto = true;
+ break;
+ case 'u':
+ num_devs = 1;
+ break;
+ case 'd':
+ start_dbus = true;
+ break;
+ case 'q':
+ qemu_binary = optarg;
+ break;
+ case 'k':
+ kernel_image = optarg;
+ break;
+ case 'v':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (run_auto) {
+ if (argc - optind > 0) {
+ fprintf(stderr, "Invalid command line parameters\n");
+ return EXIT_FAILURE;
+ }
+ } else {
+ if (argc - optind < 1) {
+ fprintf(stderr, "Failed to specify test command\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ own_binary = argv[0];
+ test_argv = argv + optind;
+ test_argc = argc - optind;
+
+ if (!qemu_binary) {
+ qemu_binary = find_qemu();
+ if (!qemu_binary) {
+ fprintf(stderr, "No default QEMU binary found\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (!kernel_image) {
+ kernel_image = find_kernel();
+ if (!kernel_image) {
+ fprintf(stderr, "No default kernel image found\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ printf("Using QEMU binary %s\n", qemu_binary);
+ printf("Using kernel image %s\n", kernel_image);
+
+ start_qemu();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/userchan-tester.c b/tools/userchan-tester.c
new file mode 100644
index 00000000..8fb08882
--- /dev/null
+++ b/tools/userchan-tester.c
@@ -0,0 +1,334 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+#include "emulator/hciemu.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hci.h"
+#include "src/shared/util.h"
+
+struct test_data {
+ struct mgmt *mgmt;
+ uint16_t mgmt_index;
+ struct hciemu *hciemu;
+ enum hciemu_type hciemu_type;
+ const void *test_data;
+ unsigned int remove_id;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct mgmt_rp_read_info *rp = param;
+ char addr[18];
+ uint16_t manufacturer;
+ uint32_t supported_settings, current_settings;
+
+ tester_print("Read Info callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ ba2str(&rp->bdaddr, addr);
+ manufacturer = btohs(rp->manufacturer);
+ supported_settings = btohl(rp->supported_settings);
+ current_settings = btohl(rp->current_settings);
+
+ tester_print(" Address: %s", addr);
+ tester_print(" Version: 0x%02x", rp->version);
+ tester_print(" Manufacturer: 0x%04x", manufacturer);
+ tester_print(" Supported settings: 0x%08x", supported_settings);
+ tester_print(" Current settings: 0x%08x", current_settings);
+ tester_print(" Class: 0x%02x%02x%02x",
+ rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+ tester_print(" Name: %s", rp->name);
+ tester_print(" Short name: %s", rp->short_name);
+
+ if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Index Added callback");
+ tester_print(" Index: 0x%04x", index);
+
+ if (data->mgmt_index != MGMT_INDEX_NONE)
+ return;
+
+ data->mgmt_index = index;
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+ read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Index Removed callback");
+ tester_print(" Index: 0x%04x", index);
+
+ if (index != data->mgmt_index)
+ return;
+
+ if (data->remove_id) {
+ mgmt_unregister(data->mgmt, data->remove_id);
+ data->remove_id = 0;
+ tester_test_passed();
+ return;
+ }
+
+ mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+ mgmt_unref(data->mgmt);
+ data->mgmt = NULL;
+
+ tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Read Index List callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+ index_added_callback, NULL, NULL);
+
+ data->hciemu = hciemu_new(data->hciemu_type);
+ if (!data->hciemu) {
+ tester_warn("Failed to setup HCI emulation");
+ tester_pre_setup_failed();
+ }
+
+ tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ data->mgmt = mgmt_new_default();
+ if (!data->mgmt) {
+ tester_warn("Failed to setup management interface");
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (tester_use_debug())
+ mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+ read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, data->mgmt_index,
+ index_removed_callback,
+ NULL, NULL);
+
+ hciemu_unref(data->hciemu);
+ data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+ struct test_data *data = test_data;
+
+ free(data);
+}
+
+static void setup_powered_client_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Controller powered on");
+
+ tester_setup_complete();
+}
+
+static void setup_powered(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Powering on controller");
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), param, setup_powered_client_callback,
+ NULL, NULL);
+}
+
+static void toggle_powered(const void *test_data);
+
+static void toggle_powered_client_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ bool power = PTR_TO_INT(user_data);
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Controller powered %s", power ? "on" : "off");
+
+ if (power)
+ toggle_powered(false);
+ else
+ tester_setup_complete();
+}
+
+static void toggle_powered(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ bool power = PTR_TO_INT(test_data);
+ unsigned char param[1];
+
+ param[0] = power ? 0x01 : 0x00;
+
+ tester_print("Powering %s controller", power ? "on" : "off");
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), param, toggle_powered_client_callback,
+ INT_TO_PTR(power), NULL);
+}
+
+static void test_open_success(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bt_hci *hci;
+
+ data->remove_id = mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED,
+ data->mgmt_index,
+ index_removed_callback,
+ NULL, NULL);
+
+ hci = bt_hci_new_user_channel(data->mgmt_index);
+ if (hci) {
+ bt_hci_unref(hci);
+ return;
+ }
+
+ mgmt_unregister(data->mgmt, data->remove_id);
+ data->remove_id = 0;
+
+ tester_test_failed();
+}
+
+static void test_open_failed(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bt_hci *hci;
+
+ hci = bt_hci_new_user_channel(data->mgmt_index);
+ if (!hci) {
+ tester_test_passed();
+ return;
+ }
+
+ bt_hci_unref(hci);
+ tester_test_failed();
+}
+
+#define test_user(name, data, setup, func) \
+ do { \
+ struct test_data *user; \
+ user = malloc(sizeof(struct test_data)); \
+ if (!user) \
+ break; \
+ user->hciemu_type = HCIEMU_TYPE_BREDR; \
+ user->mgmt_index = MGMT_INDEX_NONE; \
+ user->test_data = data; \
+ user->remove_id = 0; \
+ tester_add_full(name, data, \
+ test_pre_setup, setup, func, NULL, \
+ test_post_teardown, 2, user, test_data_free); \
+ } while (0)
+
+int main(int argc, char *argv[])
+{
+ tester_init(&argc, &argv);
+
+ test_user("User channel open - Success", NULL,
+ NULL, test_open_success);
+ test_user("User channel open - Failed", NULL,
+ setup_powered, test_open_failed);
+ test_user("User channel open - Power Toggle Success", INT_TO_PTR(true),
+ toggle_powered, test_open_success);
+
+ return tester_run();
+}
diff --git a/tools/valgrind.supp b/tools/valgrind.supp
new file mode 100644
index 00000000..9efb6f1d
--- /dev/null
+++ b/tools/valgrind.supp
@@ -0,0 +1,27 @@
+{
+ ecb_bind
+ Memcheck:Param
+ socketcall.bind(my_addr.sa_data)
+ fun:bind
+ fun:ecb_aes_setup
+}
+{
+ cmac_bind
+ Memcheck:Param
+ socketcall.bind(my_addr.sa_data)
+ fun:bind
+ fun:cmac_aes_setup
+}
+{
+ logging_open
+ Memcheck:Param
+ socketcall.bind(my_addr.rc_bdaddr)
+ fun:bind
+ fun:logging_open
+}
+{
+ bind
+ Memcheck:Param
+ socketcall.bind(my_addr.rc_channel)
+ fun:bind
+}
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 2fc7906e..01307e67 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -332,39 +332,29 @@ static void test_dummy(gconstpointer data)
static bool handle_play(struct avrcp *session, bool pressed, void *user_data)
{
- DBG("");
-
return true;
}
static bool handle_volume_up(struct avrcp *session, bool pressed,
void *user_data)
{
- DBG("");
-
return true;
}
static bool handle_channel_up(struct avrcp *session, bool pressed,
void *user_data)
{
- DBG("");
-
return true;
}
static bool handle_select(struct avrcp *session, bool pressed, void *user_data)
{
- DBG("");
-
return true;
}
static bool handle_vendor_uniq(struct avrcp *session, bool pressed,
void *user_data)
{
- DBG("");
-
return true;
}
@@ -386,8 +376,6 @@ static int get_capabilities(struct avrcp *session, uint8_t transaction,
static int list_attributes(struct avrcp *session, uint8_t transaction,
void *user_data)
{
- DBG("");
-
avrcp_list_player_attributes_rsp(session, transaction, 0, NULL);
return 0;
@@ -399,8 +387,6 @@ static int get_attribute_text(struct avrcp *session, uint8_t transaction,
{
const char *text[number];
- DBG("");
-
if (number) {
memset(text, 0, number);
text[0] = "equalizer";
@@ -415,8 +401,6 @@ static int get_attribute_text(struct avrcp *session, uint8_t transaction,
static int list_values(struct avrcp *session, uint8_t transaction,
uint8_t attr, void *user_data)
{
- DBG("");
-
avrcp_list_player_values_rsp(session, transaction, 0, NULL);
return -EINVAL;
@@ -428,8 +412,6 @@ static int get_value_text(struct avrcp *session, uint8_t transaction,
{
const char *text[number];
- DBG("");
-
if (number) {
memset(text, 0, number);
text[0] = "on";
@@ -446,8 +428,6 @@ static int get_value(struct avrcp *session, uint8_t transaction,
{
uint8_t values[number];
- DBG("");
-
memset(values, 0, number);
avrcp_get_current_player_value_rsp(session, transaction, number, attrs,
@@ -460,8 +440,6 @@ static int set_value(struct avrcp *session, uint8_t transaction,
uint8_t number, uint8_t *attrs, uint8_t *values,
void *user_data)
{
- DBG("");
-
avrcp_set_player_value_rsp(session, transaction);
return 0;
@@ -470,8 +448,6 @@ static int set_value(struct avrcp *session, uint8_t transaction,
static int get_play_status(struct avrcp *session, uint8_t transaction,
void *user_data)
{
- DBG("");
-
avrcp_get_play_status_rsp(session, transaction, 0xaaaaaaaa, 0xbbbbbbbb,
0x00);
@@ -484,8 +460,6 @@ static int get_element_attributes(struct avrcp *session, uint8_t transaction,
{
struct context *context = user_data;
- DBG("");
-
if (g_str_has_prefix(context->data->test_name, "/TP/RCR")) {
uint8_t params[1024];
@@ -506,8 +480,6 @@ static int track_changed(struct avrcp *session, uint8_t transaction,
struct context *context = user_data;
uint64_t track;
- DBG("");
-
if (g_str_equal(context->data->test_name, "/TP/NFY/BV-05-C") ||
g_str_equal(context->data->test_name, "/TP/NFY/BV-08-C"))
memset(&track, 0, sizeof(track));
@@ -530,8 +502,6 @@ static int settings_changed(struct avrcp *session, uint8_t transaction,
{
uint8_t settings[3];
- DBG("");
-
settings[0] = 0x01;
settings[1] = 0x01;
settings[2] = 0x02;
@@ -550,8 +520,6 @@ static int settings_changed(struct avrcp *session, uint8_t transaction,
static int available_players_changed(struct avrcp *session, uint8_t transaction,
uint32_t interval, void *user_data)
{
- DBG("");
-
avrcp_register_notification_rsp(session, transaction, AVC_CTYPE_INTERIM,
AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED,
NULL, 0);
@@ -568,8 +536,6 @@ static int addressed_player_changed(struct avrcp *session, uint8_t transaction,
{
uint16_t player[2];
- DBG("");
-
player[0] = 0x0001;
player[1] = 0x0001;
@@ -593,8 +559,6 @@ static int uids_changed(struct avrcp *session, uint8_t transaction,
struct context *context = user_data;
uint16_t counter;
- DBG("");
-
if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BV-09-C"))
counter = 0x0000;
else
@@ -621,8 +585,6 @@ static int now_playing_content_changed(struct avrcp *session,
uint8_t transaction, uint32_t interval,
void *user_data)
{
- DBG("");
-
avrcp_register_notification_rsp(session, transaction, AVC_CTYPE_INTERIM,
AVRCP_EVENT_NOW_PLAYING_CONTENT_CHANGED,
NULL, 0);
@@ -639,8 +601,6 @@ static int volume_changed(struct avrcp *session, uint8_t transaction,
{
uint8_t volume = 0x00;
- DBG("");
-
avrcp_register_notification_rsp(session, transaction, AVC_CTYPE_INTERIM,
AVRCP_EVENT_VOLUME_CHANGED,
&volume, sizeof(volume));
@@ -658,8 +618,6 @@ static int register_notification(struct avrcp *session, uint8_t transaction,
uint8_t event, uint32_t interval,
void *user_data)
{
- DBG("");
-
switch (event) {
case AVRCP_EVENT_TRACK_CHANGED:
return track_changed(session, transaction, interval, user_data);
@@ -688,8 +646,6 @@ static int register_notification(struct avrcp *session, uint8_t transaction,
static int set_volume(struct avrcp *session, uint8_t transaction,
uint8_t volume, void *user_data)
{
- DBG("");
-
avrcp_set_volume_rsp(session, transaction, volume);
return 0;
@@ -701,8 +657,6 @@ static int set_addressed(struct avrcp *session, uint8_t transaction,
struct context *context = user_data;
uint8_t status;
- DBG("");
-
if (g_str_equal(context->data->test_name, "/TP/MPS/BI-01-C"))
status = AVRCP_STATUS_INVALID_PLAYER_ID;
else
@@ -719,8 +673,6 @@ static int set_browsed(struct avrcp *session, uint8_t transaction,
struct context *context = user_data;
const char *folders[1] = { "Filesystem" };
- DBG("");
-
if (g_str_equal(context->data->test_name, "/TP/MPS/BI-02-C"))
avrcp_set_browsed_player_rsp(session, transaction,
AVRCP_STATUS_INVALID_PLAYER_ID,
@@ -740,8 +692,6 @@ static int get_folder_items(struct avrcp *session, uint8_t transaction,
{
struct context *context = user_data;
- DBG("");
-
if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BI-02-C"))
return -ERANGE;
@@ -758,8 +708,6 @@ static int change_path(struct avrcp *session, uint8_t transaction,
uint16_t counter, uint8_t direction,
uint64_t uid, void *user_data)
{
- DBG("");
-
if (!uid)
return -ENOTDIR;
@@ -776,8 +724,6 @@ static int get_item_attributes(struct avrcp *session, uint8_t transaction,
struct context *context = user_data;
uint8_t status;
- DBG("");
-
if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BI-05-C"))
status = AVRCP_STATUS_UID_CHANGED;
else
@@ -792,8 +738,6 @@ static int get_item_attributes(struct avrcp *session, uint8_t transaction,
static int play_item(struct avrcp *session, uint8_t transaction, uint8_t scope,
uint64_t uid, uint16_t counter, void *user_data)
{
- DBG("");
-
if (!uid)
return -ENOENT;
@@ -805,8 +749,6 @@ static int play_item(struct avrcp *session, uint8_t transaction, uint8_t scope,
static int search(struct avrcp *session, uint8_t transaction,
const char *string, void *user_data)
{
- DBG("");
-
avrcp_search_rsp(session, transaction, AVRCP_STATUS_SUCCESS, 0xaabb, 0);
return 0;
@@ -816,8 +758,6 @@ static int add_to_now_playing(struct avrcp *session, uint8_t transaction,
uint8_t scope, uint64_t uid, uint16_t counter,
void *user_data)
{
- DBG("");
-
if (!uid)
return -ENOENT;
@@ -858,8 +798,6 @@ static void test_server(gconstpointer data)
avrcp_register_player(context->session, &control_ind, NULL, context);
g_idle_add(send_pdu, context);
-
- execute_context(context);
}
static void get_folder_items_rsp(struct avrcp *session, int err,
@@ -868,8 +806,6 @@ static void get_folder_items_rsp(struct avrcp *session, int err,
{
struct context *context = user_data;
- DBG("");
-
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(counter, ==, 0xabcd);
g_assert_cmpint(number, ==, 0);
@@ -890,24 +826,23 @@ static void set_volume_rsp(struct avrcp *session, int err, uint8_t volume,
static bool register_notification_rsp(struct avrcp *session, int err,
uint8_t code, uint8_t event,
- uint8_t *params, void *user_data)
+ void *params, void *user_data)
{
struct context *context = user_data;
-
- DBG("");
+ uint8_t *p = params;
g_assert_cmpint(err, ==, 0);
switch (event) {
case AVRCP_EVENT_VOLUME_CHANGED:
if (g_str_equal(context->data->test_name, "/TP/VLH/BV-03-C")) {
- g_assert_cmpint(params[0], ==, 0);
+ g_assert_cmpint(p[0], ==, 0);
break;
} else if (code == AVC_CTYPE_INTERIM) {
- g_assert_cmpint(params[0], ==, 0);
+ g_assert_cmpint(p[0], ==, 0);
return true;
}
- g_assert_cmpint(params[0], ==, 1);
+ g_assert_cmpint(p[0], ==, 1);
break;
}
diff --git a/unit/test-crc.c b/unit/test-crc.c
index db40dc90..791fa513 100644
--- a/unit/test-crc.c
+++ b/unit/test-crc.c
@@ -26,6 +26,7 @@
#endif
#include "monitor/crc.h"
+#include "src/shared/tester.h"
#include <glib.h>
@@ -160,35 +161,33 @@ static void test_crc(gconstpointer data)
crc = crc24_calculate(crc_init, test_data->packet + 4,
test_data->size - 7);
- if (g_test_verbose())
- g_print("CRC: 0x%6.6x, Calculated: 0x%6.6x\n",
- crc_value, crc);
+ tester_debug("CRC: 0x%6.6x, Calculated: 0x%6.6x", crc_value, crc);
g_assert(crc_value == crc);
rev = crc24_reverse(crc_value, test_data->packet + 4,
test_data->size - 7);
- if (g_test_verbose())
- g_print("Preset: 0x%6.6x, Calculated: 0x%6.6x\n",
- crc_init, rev);
+ tester_debug("Preset: 0x%6.6x, Calculated: 0x%6.6x", crc_init, rev);
g_assert(crc_init == rev);
+
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_data_func("/crc/1", &crc_1, test_crc);
- g_test_add_data_func("/crc/2", &crc_2, test_crc);
- g_test_add_data_func("/crc/3", &crc_3, test_crc);
- g_test_add_data_func("/crc/4", &crc_4, test_crc);
- g_test_add_data_func("/crc/5", &crc_5, test_crc);
- g_test_add_data_func("/crc/6", &crc_6, test_crc);
- g_test_add_data_func("/crc/7", &crc_7, test_crc);
- g_test_add_data_func("/crc/8", &crc_8, test_crc);
- g_test_add_data_func("/crc/9", &crc_9, test_crc);
-
- return g_test_run();
+ tester_init(&argc, &argv);
+
+ tester_add("/crc/1", &crc_1, NULL, test_crc, NULL);
+ tester_add("/crc/2", &crc_2, NULL, test_crc, NULL);
+ tester_add("/crc/3", &crc_3, NULL, test_crc, NULL);
+ tester_add("/crc/4", &crc_4, NULL, test_crc, NULL);
+ tester_add("/crc/5", &crc_5, NULL, test_crc, NULL);
+ tester_add("/crc/6", &crc_6, NULL, test_crc, NULL);
+ tester_add("/crc/7", &crc_7, NULL, test_crc, NULL);
+ tester_add("/crc/8", &crc_8, NULL, test_crc, NULL);
+ tester_add("/crc/9", &crc_9, NULL, test_crc, NULL);
+
+ return tester_run();
}
diff --git a/unit/test-crypto.c b/unit/test-crypto.c
index fd2ea78c..5fb1c64c 100644
--- a/unit/test-crypto.c
+++ b/unit/test-crypto.c
@@ -26,6 +26,8 @@
#endif
#include "src/shared/crypto.h"
+#include "src/shared/util.h"
+#include "src/shared/tester.h"
#include <string.h>
#include <glib.h>
@@ -107,14 +109,9 @@ static const struct test_data test_data_4 = {
.t = t_msg_4
};
-static void print_buf(const uint8_t *t, uint8_t len)
+static void print_debug(const char *str, void *user_data)
{
- int i;
-
- for (i = 0; i < len; i++)
- g_print("0x%02x, ", t[i]);
-
- g_print("\n");
+ tester_debug("%s", str);
}
static bool result_compare(const uint8_t exp[12], uint8_t res[12])
@@ -136,14 +133,14 @@ static void test_sign(gconstpointer data)
if (!bt_crypto_sign_att(crypto, key, d->msg, d->msg_len, 0, t))
g_assert(true);
- if (g_test_verbose()) {
- g_print("Result T: ");
- print_buf(t, 12);
- g_print("Expected T:");
- print_buf(d->t, 12);
- }
+ tester_debug("Result T:");
+ util_hexdump(' ', t, 12, print_debug, NULL);
+ tester_debug("Expected T:");
+ util_hexdump(' ', d->t, 12, print_debug, NULL);
g_assert(result_compare(d->t, t));
+
+ tester_test_passed();
}
int main(int argc, char *argv[])
@@ -154,14 +151,14 @@ int main(int argc, char *argv[])
if (!crypto)
return 0;
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- g_test_add_data_func("/crypto/sign_att_1", &test_data_1, test_sign);
- g_test_add_data_func("/crypto/sign_att_2", &test_data_2, test_sign);
- g_test_add_data_func("/crypto/sign_att_3", &test_data_3, test_sign);
- g_test_add_data_func("/crypto/sign_att_4", &test_data_4, test_sign);
+ tester_add("/crypto/sign_att_1", &test_data_1, NULL, test_sign, NULL);
+ tester_add("/crypto/sign_att_2", &test_data_2, NULL, test_sign, NULL);
+ tester_add("/crypto/sign_att_3", &test_data_3, NULL, test_sign, NULL);
+ tester_add("/crypto/sign_att_4", &test_data_4, NULL, test_sign, NULL);
- exit_status = g_test_run();
+ exit_status = tester_run();
bt_crypto_unref(crypto);
diff --git a/unit/test-ecc.c b/unit/test-ecc.c
index 8f801187..9b48d0b3 100644
--- a/unit/test-ecc.c
+++ b/unit/test-ecc.c
@@ -37,33 +37,33 @@
#include <fcntl.h>
#include "src/shared/ecc.h"
+#include "src/shared/util.h"
+#include "src/shared/tester.h"
-static void vli_print(uint8_t *vli, size_t size)
+static void print_dump(const char *str, void *user_data)
{
- while (size) {
- printf("%02X ", vli[size - 1]);
- size--;
- }
+ tester_debug("%s", str);
+}
+
+static void print_buf(const char *label, uint8_t *buf, size_t len)
+{
+ tester_debug("%s", label);
+
+ util_hexdump(' ', buf, len, print_dump, NULL);
}
#define PAIR_COUNT 200
-static void test_multi(void)
+static void test_multi(const void *data)
{
uint8_t public1[64], public2[64];
uint8_t private1[32], private2[32];
uint8_t shared1[32], shared2[32];
int i;
- if (g_test_verbose())
- g_print("Testing %u random private key pairs", PAIR_COUNT);
+ tester_debug("Testing %u random private key pairs", PAIR_COUNT);
for (i = 0; i < PAIR_COUNT; i++) {
- if (g_test_verbose()) {
- printf(".");
- fflush(stdout);
- }
-
ecc_make_key(public1, private1);
ecc_make_key(public2, private2);
@@ -71,37 +71,20 @@ static void test_multi(void)
ecdh_shared_secret(public2, private1, shared2);
if (memcmp(shared1, shared2, sizeof(shared1)) != 0) {
- printf("Shared secrets are not identical!\n");
- printf("Shared secret 1 = ");
- vli_print(shared1, sizeof(shared1));
- printf("\n");
- printf("Shared secret 2 = ");
- vli_print(shared2, sizeof(shared2));
- printf("\n");
- printf("Private key 1 = ");
- vli_print(private1, sizeof(private1));
- printf("\n");
- printf("Private key 2 = ");
- vli_print(private2, sizeof(private2));
- printf("\n");
+ tester_debug("Shared secrets are not identical!\n");
+ print_buf("Shared secret 1 = ", shared1,
+ sizeof(shared1));
+ print_buf("Shared secret 2 = ", shared2,
+ sizeof(shared2));
+ print_buf("Private key 1 = ", private1,
+ sizeof(private1));
+ print_buf("Private key 2 = ", private2,
+ sizeof(private2));
g_assert_not_reached();
}
}
- if (g_test_verbose())
- printf("\n");
-}
-
-static void print_buf(const char *label, uint8_t *buf, size_t len)
-{
- size_t i;
-
- printf("%s ", label);
-
- for (i = 0; i < len; i++)
- printf("%02x", buf[i]);
-
- printf("\n");
+ tester_test_passed();
}
static int test_sample(uint8_t priv_a[32], uint8_t priv_b[32],
@@ -121,27 +104,23 @@ static int test_sample(uint8_t priv_a[32], uint8_t priv_b[32],
}
if (memcmp(dhkey_a, dhkey, 32)) {
- if (g_test_verbose())
- printf("DHKey A doesn't match!\n");
+ tester_debug("DHKey A doesn't match!");
fails++;
} else {
- if (g_test_verbose())
- printf("DHKey A matches :)\n");
+ tester_debug("DHKey A matches :)");
}
if (memcmp(dhkey_b, dhkey, 32)) {
- if (g_test_verbose())
- printf("DHKey B doesn't match!\n");
+ tester_debug("DHKey B doesn't match!");
fails++;
} else {
- if (g_test_verbose())
- printf("DHKey B matches :)\n");
+ tester_debug("DHKey B matches :)");
}
return fails;
}
-static void test_sample_1(void)
+static void test_sample_1(const void *data)
{
uint8_t priv_a[32] = { 0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,
0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,
@@ -183,9 +162,11 @@ static void test_sample_1(void)
fails = test_sample(priv_a, priv_b, pub_a, pub_b, dhkey);
g_assert(fails == 0);
+
+ tester_test_passed();
}
-static void test_sample_2(void)
+static void test_sample_2(const void *data)
{
uint8_t priv_a[32] = { 0x63, 0x76, 0x45, 0xd0, 0xf7, 0x73, 0xac, 0xb7,
0xff, 0xdd, 0x03, 0x72, 0xb9, 0x72, 0x85, 0xb4,
@@ -227,9 +208,11 @@ static void test_sample_2(void)
fails = test_sample(priv_a, priv_b, pub_a, pub_b, dhkey);
g_assert(fails == 0);
+
+ tester_test_passed();
}
-static void test_sample_3(void)
+static void test_sample_3(const void *data)
{
uint8_t priv_a[32] = { 0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,
0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,
@@ -256,17 +239,19 @@ static void test_sample_3(void)
fails = test_sample(priv_a, priv_a, pub_a, pub_a, dhkey);
g_assert(fails == 0);
+
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- g_test_add_func("/ecdh/multi", test_multi);
+ tester_add("/ecdh/multi", NULL, NULL, test_multi, NULL);
- g_test_add_func("/ecdh/sample/1", test_sample_1);
- g_test_add_func("/ecdh/sample/2", test_sample_2);
- g_test_add_func("/ecdh/sample/3", test_sample_3);
+ tester_add("/ecdh/sample/1", NULL, NULL, test_sample_1, NULL);
+ tester_add("/ecdh/sample/2", NULL, NULL, test_sample_2, NULL);
+ tester_add("/ecdh/sample/3", NULL, NULL, test_sample_3, NULL);
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-eir.c b/unit/test-eir.c
index 043634b6..421d0db1 100644
--- a/unit/test-eir.c
+++ b/unit/test-eir.c
@@ -32,7 +32,8 @@
#include "lib/bluetooth.h"
#include "lib/hci.h"
#include "lib/sdp.h"
-
+#include "src/shared/tester.h"
+#include "src/shared/util.h"
#include "src/eir.h"
struct test_data {
@@ -527,44 +528,51 @@ static const struct test_data citizen_scan_test = {
.uuid = citizen_scan_uuid,
};
-static void test_basic(void)
+static void test_basic(const void *data)
{
- struct eir_data data;
+ struct eir_data eir;
unsigned char buf[HCI_MAX_EIR_LENGTH];
memset(buf, 0, sizeof(buf));
- memset(&data, 0, sizeof(data));
+ memset(&eir, 0, sizeof(eir));
- eir_parse(&data, buf, HCI_MAX_EIR_LENGTH);
- g_assert(data.services == NULL);
- g_assert(data.name == NULL);
+ eir_parse(&eir, buf, HCI_MAX_EIR_LENGTH);
+ g_assert(eir.services == NULL);
+ g_assert(eir.name == NULL);
+
+ eir_data_free(&eir);
+
+ tester_test_passed();
+}
+
+static void print_debug(const char *str, void *user_data)
+{
+ char *prefix = user_data;
- eir_data_free(&data);
+ tester_debug("%s%s", prefix, str);
}
static void test_parsing(gconstpointer data)
{
const struct test_data *test = data;
struct eir_data eir;
+ GSList *list;
memset(&eir, 0, sizeof(eir));
eir_parse(&eir, test->eir_data, test->eir_size);
- if (g_test_verbose() == TRUE) {
- GSList *list;
+ tester_debug("Flags: %d", eir.flags);
+ tester_debug("Name: %s", eir.name);
+ tester_debug("TX power: %d", eir.tx_power);
- g_print("Flags: %d\n", eir.flags);
- g_print("Name: %s\n", eir.name);
- g_print("TX power: %d\n", eir.tx_power);
+ for (list = eir.services; list; list = list->next) {
+ char *uuid_str = list->data;
- for (list = eir.services; list; list = list->next) {
- char *uuid_str = list->data;
- g_print("UUID: %s\n", uuid_str);
- }
+ tester_debug("UUID: %s", uuid_str);
}
- g_assert(eir.flags == test->flags);
+ g_assert_cmpint(eir.flags, ==, test->flags);
if (test->name) {
g_assert_cmpstr(eir.name, ==, test->name);
@@ -588,28 +596,89 @@ static void test_parsing(gconstpointer data)
g_assert(eir.services == NULL);
}
+ for (list = eir.msd_list; list; list = list->next) {
+ struct eir_msd *msd = list->data;
+
+ tester_debug("Manufacturer ID: 0x%04x", msd->company);
+ util_hexdump(' ', msd->data, msd->data_len, print_debug,
+ "Manufacturer Data:");
+ }
+
+ for (list = eir.sd_list; list; list = list->next) {
+ struct eir_sd *sd = list->data;
+
+ tester_debug("Service UUID: %s", sd->uuid);
+ util_hexdump(' ', sd->data, sd->data_len, print_debug,
+ "Service Data:");
+ }
+
eir_data_free(&eir);
+
+ tester_test_passed();
}
+static const unsigned char gigaset_gtag_data[] = {
+ 0x02, 0x01, 0x06, 0x0d, 0xff, 0x80, 0x01, 0x02,
+ 0x15, 0x12, 0x34, 0x80, 0x91, 0xd0, 0xf2, 0xbb,
+ 0xc5, 0x03, 0x02, 0x0f, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const char *gigaset_gtag_uuid[] = {
+ "0000180f-0000-1000-8000-00805f9b34fb",
+ NULL
+};
+
+static const struct test_data gigaset_gtag_test = {
+ .eir_data = gigaset_gtag_data,
+ .eir_size = sizeof(gigaset_gtag_data),
+ .flags = 0x06,
+ .tx_power = 127,
+ .uuid = gigaset_gtag_uuid,
+};
+
+static const char *uri_beacon_uuid[] = {
+ "0000fed8-0000-1000-8000-00805f9b34fb",
+ NULL
+};
+
+static const unsigned char uri_beacon_data[] = {
+ 0x03, 0x03, 0xd8, 0xfe, 0x0c, 0x16, 0xd8, 0xfe, 0x00,
+ 0x20, 0x00, 'b', 'l', 'u', 'e', 'z', 0x08
+};
+
+static const struct test_data uri_beacon_test = {
+ .eir_data = uri_beacon_data,
+ .eir_size = sizeof(uri_beacon_data),
+ .tx_power = 127,
+ .uuid = uri_beacon_uuid,
+};
+
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/eir/basic", test_basic);
-
- g_test_add_data_func("/eir/macbookair", &macbookair_test, test_parsing);
- g_test_add_data_func("/eir/iphone5", &iphone5_test, test_parsing);
- g_test_add_data_func("/eir/ipadmini", &ipadmini_test, test_parsing);
- g_test_add_data_func("/eir/sl400h", &gigaset_sl400h_test, test_parsing);
- g_test_add_data_func("/eir/sl910", &gigaset_sl910_test, test_parsing);
- g_test_add_data_func("/eir/bh907", &nokia_bh907_test, test_parsing);
- g_test_add_data_func("/eir/fuelband", &fuelband_test, test_parsing);
- g_test_add_data_func("/ad/bluesc", &bluesc_test, test_parsing);
- g_test_add_data_func("/ad/wahooscale", &wahoo_scale_test, test_parsing);
- g_test_add_data_func("/ad/mioalpha", &mio_alpha_test, test_parsing);
- g_test_add_data_func("/ad/cookoo", &cookoo_test, test_parsing);
- g_test_add_data_func("/ad/citizen1", &citizen_adv_test, test_parsing);
- g_test_add_data_func("/ad/citizen2", &citizen_scan_test, test_parsing);
-
- return g_test_run();
+ tester_init(&argc, &argv);
+
+ tester_add("/eir/basic", NULL, NULL, test_basic, NULL);
+
+ tester_add("/eir/macbookair", &macbookair_test, NULL, test_parsing,
+ NULL);
+ tester_add("/eir/iphone5", &iphone5_test, NULL, test_parsing, NULL);
+ tester_add("/eir/ipadmini", &ipadmini_test, NULL, test_parsing, NULL);
+ tester_add("/eir/sl400h", &gigaset_sl400h_test, NULL, test_parsing,
+ NULL);
+ tester_add("/eir/sl910", &gigaset_sl910_test, NULL, test_parsing, NULL);
+ tester_add("/eir/bh907", &nokia_bh907_test, NULL, test_parsing, NULL);
+ tester_add("/eir/fuelband", &fuelband_test, NULL, test_parsing, NULL);
+ tester_add("/ad/bluesc", &bluesc_test, NULL, test_parsing, NULL);
+ tester_add("/ad/wahooscale", &wahoo_scale_test, NULL, test_parsing,
+ NULL);
+ tester_add("/ad/mioalpha", &mio_alpha_test, NULL, test_parsing, NULL);
+ tester_add("/ad/cookoo", &cookoo_test, NULL, test_parsing, NULL);
+ tester_add("/ad/citizen1", &citizen_adv_test, NULL, test_parsing, NULL);
+ tester_add("/ad/citizen2", &citizen_scan_test, NULL, test_parsing,
+ NULL);
+ tester_add("ad/g-tag", &gigaset_gtag_test, NULL, test_parsing, NULL);
+ tester_add("ad/uri-beacon", &uri_beacon_test, NULL, test_parsing, NULL);
+
+ return tester_run();
}
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 95b42dd7..326a32c7 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -630,6 +630,10 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
if (context->data->step) {
const struct test_step *step = context->data->step;
+ /* Auto elevate security for test that don't expect error */
+ if (!step->expected_att_ecode)
+ bt_att_set_security(context->att, BT_ATT_SECURITY_AUTO);
+
step->func(context);
return;
}
@@ -647,7 +651,7 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
g_assert(err == 0);
- context->att = bt_att_new(sv[0]);
+ context->att = bt_att_new(sv[0], false);
g_assert(context->att);
switch (test_data->context_type) {
@@ -1002,7 +1006,7 @@ static void test_signed_write_seclevel(struct context *context)
g_assert(bt_att_set_local_key(context->att, key, local_counter,
context));
- g_assert(bt_att_set_sec_level(context->att, BT_SECURITY_MEDIUM));
+ g_assert(bt_att_set_security(context->att, BT_ATT_SECURITY_MEDIUM));
g_assert(bt_gatt_client_write_without_response(context->client,
step->handle,
@@ -1090,6 +1094,125 @@ static const struct test_step test_long_write_6 = {
.length = 0x03
};
+static const struct test_step test_long_write_7 = {
+ .handle = 0x0008,
+ .func = test_long_write,
+ .expected_att_ecode = 0,
+ .value = long_data_2,
+ .length = sizeof(long_data_2)
+};
+
+static const struct test_step test_long_write_8 = {
+ .handle = 0x0000,
+ .func = test_long_write,
+ .expected_att_ecode = 0x01,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_long_write_9 = {
+ .handle = 0x0008,
+ .func = test_long_write,
+ .expected_att_ecode = 0x03,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_long_write_10 = {
+ .handle = 0x0008,
+ .func = test_long_write,
+ .expected_att_ecode = 0x08,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_long_write_11 = {
+ .handle = 0x0008,
+ .func = test_long_write,
+ .expected_att_ecode = 0x05,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_long_write_12 = {
+ .handle = 0x0008,
+ .func = test_long_write,
+ .expected_att_ecode = 0x0c,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static void test_reliable_write_cb(bool success, bool reliable_error,
+ uint8_t att_ecode, void *user_data)
+{
+ struct context *context = user_data;
+ const struct test_step *step = context->data->step;
+
+ g_assert(att_ecode == step->expected_att_ecode);
+
+ g_assert(!reliable_error);
+
+ context_quit(context);
+}
+
+static void test_reliable_write(struct context *context)
+{
+ const struct test_step *step = context->data->step;
+
+ g_assert(bt_gatt_client_write_long_value(context->client, true,
+ step->handle, 0, step->value,
+ step->length, test_reliable_write_cb,
+ context, NULL));
+}
+
+static const struct test_step test_reliable_write_1 = {
+ .handle = 0x0007,
+ .func = test_reliable_write,
+ .expected_att_ecode = 0,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_reliable_write_2 = {
+ .handle = 0x0000,
+ .func = test_reliable_write,
+ .expected_att_ecode = 0x01,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_reliable_write_3 = {
+ .handle = 0x0003,
+ .func = test_reliable_write,
+ .expected_att_ecode = 0x03,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_reliable_write_4 = {
+ .handle = 0x0007,
+ .func = test_reliable_write,
+ .expected_att_ecode = 0x08,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_reliable_write_5 = {
+ .handle = 0x0007,
+ .func = test_reliable_write,
+ .expected_att_ecode = 0x05,
+ .value = write_data_1,
+ .length = 0x03
+};
+
+static const struct test_step test_reliable_write_6 = {
+ .handle = 0x0007,
+ .func = test_reliable_write,
+ .expected_att_ecode = 0x0c,
+ .value = write_data_1,
+ .length = 0x03
+};
+
static void att_write_cb(struct gatt_db_attribute *att, int err,
void *user_data)
{
@@ -2568,6 +2691,14 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x05));
+ define_test_client("/TP/GAR/CL/BI-04-C/auto", test_client, service_db_1,
+ &test_read_1,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x0a, 0x03, 0x00),
+ raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x05),
+ raw_pdu(0x0a, 0x03, 0x00),
+ raw_pdu(0x0b, 0x01, 0x02, 0x03));
+
define_test_client("/TP/GAR/CL/BI-05-C", test_client, service_db_1,
&test_read_6,
SERVICE_DATA_1_PDUS,
@@ -2762,7 +2893,7 @@ int main(int argc, char *argv[])
&test_long_read_1,
SERVICE_DATA_1_PDUS,
raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
- raw_pdu(0x0b, 0x01, 0x02, 0x03));
+ raw_pdu(0x0d, 0x01, 0x02, 0x03));
define_test_client("/TP/GAR/CL/BV-04-C/512B", test_client, service_db_1,
&test_long_read_2,
@@ -2910,6 +3041,14 @@ int main(int argc, char *argv[])
raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x05));
+ define_test_client("/TP/GAR/CL/BI-16-C/auto", test_client, service_db_1,
+ &test_long_read_1,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+ raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x05),
+ raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+ raw_pdu(0x0d, 0x01, 0x02, 0x03));
+
define_test_client("/TP/GAR/CL/BI-17-C", test_client, service_db_1,
&test_long_read_8,
SERVICE_DATA_1_PDUS,
@@ -2940,6 +3079,14 @@ int main(int argc, char *argv[])
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x05));
+ define_test_client("/TP/GAR/CL/BI-21-C/auto", test_client, service_db_1,
+ &test_multiple_read_1,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x05),
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x0f, 0x01, 0x02, 0x03));
+
define_test_client("/TP/GAR/CL/BI-22-C", test_client, service_db_1,
&test_multiple_read_6,
SERVICE_DATA_1_PDUS,
@@ -3135,6 +3282,14 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x04, 0x00),
raw_pdu(0x01, 0x0a, 0x04, 0x00, 0x05));
+ define_test_client("/TP/GAR/CL/BI-26-C/auto", test_client, service_db_1,
+ &test_read_7,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x0a, 0x04, 0x00),
+ raw_pdu(0x01, 0x0a, 0x04, 0x00, 0x05),
+ raw_pdu(0x0a, 0x04, 0x00),
+ raw_pdu(0x0b, 0x01, 0x02, 0x03));
+
define_test_client("/TP/GAR/CL/BI-27-C", test_client, service_db_1,
&test_read_11,
SERVICE_DATA_1_PDUS,
@@ -3145,7 +3300,7 @@ int main(int argc, char *argv[])
&test_long_read_9,
SERVICE_DATA_1_PDUS,
raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
- raw_pdu(0x0b, 0x01, 0x02, 0x03));
+ raw_pdu(0x0d, 0x01, 0x02, 0x03));
define_test_client("/TP/GAR/CL/BV-07-C/512B", test_client, service_db_1,
&test_long_read_10,
@@ -3287,6 +3442,14 @@ int main(int argc, char *argv[])
raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x05));
+ define_test_client("/TP/GAR/CL/BI-32-C/auto", test_client, service_db_1,
+ &test_long_read_9,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+ raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x05),
+ raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+ raw_pdu(0x0d, 0x01, 0x02, 0x03));
+
define_test_client("/TP/GAR/CL/BI-33-C", test_client, service_db_1,
&test_long_read_15,
SERVICE_DATA_1_PDUS,
@@ -3352,6 +3515,14 @@ int main(int argc, char *argv[])
raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
raw_pdu(0x01, 0x12, 0x07, 0x00, 0x05));
+ define_test_client("/TP/GAW/CL/BI-05-C/auto", test_client, service_db_1,
+ &test_write_1,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x12, 0x07, 0x00, 0x05),
+ raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x13));
+
define_test_client("/TP/GAW/CL/BI-06-C", test_client, service_db_1,
&test_write_6,
SERVICE_DATA_1_PDUS,
@@ -3732,6 +3903,64 @@ int main(int argc, char *argv[])
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
raw_pdu(0x01, 0x16, 0x73, 0x00, 0x03));
+ define_test_client("/TP/GAW/CL/BV-06-C", test_client, service_db_1,
+ &test_reliable_write_1,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x17, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x18, 0x01),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-14-C", test_client, service_db_1,
+ &test_reliable_write_2,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x00, 0x00, 0x01),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-15-C", test_client, service_db_1,
+ &test_reliable_write_3,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x03, 0x00, 0x03),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-17-C", test_client, service_db_1,
+ &test_reliable_write_4,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x07, 0x00, 0x08),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-18-C", test_client, service_db_1,
+ &test_reliable_write_5,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x07, 0x00, 0x05),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-18-C/auto", test_client, service_db_1,
+ &test_reliable_write_1,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x07, 0x00, 0x05),
+ raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x17, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x18, 0x01),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-19-C", test_client, service_db_1,
+ &test_reliable_write_6,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x07, 0x00, 0x0c),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
define_test_server("/TP/GAW/SR/BV-06-C/small", test_server,
ts_small_db, NULL,
raw_pdu(0x03, 0x00, 0x02),
@@ -3830,6 +4059,14 @@ int main(int argc, char *argv[])
raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
raw_pdu(0x01, 0x12, 0x08, 0x00, 0x05));
+ define_test_client("/TP/GAW/CL/BI-23-C/auto", test_client, service_db_1,
+ &test_write_7,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x12, 0x08, 0x00, 0x05),
+ raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x13));
+
define_test_client("/TP/GAW/CL/BI-24-C", test_client, service_db_1,
&test_write_12,
SERVICE_DATA_1_PDUS,
@@ -3872,6 +4109,262 @@ int main(int argc, char *argv[])
raw_pdu(0x12, 0x04, 0x00, 0x01, 0x02, 0x03),
raw_pdu(0x01, 0x12, 0x04, 0x00, 0x03));
+ define_test_client("/TP/GAW/CL/BV-09-C", test_client, service_db_1,
+ &test_long_write_7,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x08, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff),
+ raw_pdu(0x17, 0x08, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff),
+ raw_pdu(0x16, 0x08, 0x00, 0xfb, 0x01,
+ 0xff, 0xff, 0xff, 0xff, 0xff),
+ raw_pdu(0x17, 0x08, 0x00, 0xfb, 0x01,
+ 0xff, 0xff, 0xff, 0xff, 0xff),
+ raw_pdu(0x18, 0x01),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-25-C", test_client, service_db_1,
+ &test_long_write_8,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x00, 0x00, 0x01),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-26-C", test_client, service_db_1,
+ &test_long_write_9,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x08, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x08, 0x00, 0x03),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-29-C", test_client, service_db_1,
+ &test_long_write_10,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x08, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x08, 0x00, 0x08),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-30-C", test_client, service_db_1,
+ &test_long_write_11,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x08, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x08, 0x00, 0x05),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
+ define_test_client("/TP/GAW/CL/BI-31-C", test_client, service_db_1,
+ &test_long_write_12,
+ SERVICE_DATA_1_PDUS,
+ raw_pdu(0x16, 0x08, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x01, 0x16, 0x08, 0x00, 0x0c),
+ raw_pdu(0x18, 0x00),
+ raw_pdu(0x19));
+
define_test_server("/TP/GAW/SR/BV-09-C/small", test_server,
ts_small_db, NULL,
raw_pdu(0x03, 0x00, 0x02),
diff --git a/unit/test-gattrib.c b/unit/test-gattrib.c
index 28542f3c..416e5963 100644
--- a/unit/test-gattrib.c
+++ b/unit/test-gattrib.c
@@ -92,7 +92,7 @@ static void setup_context(struct context *cxt, gconstpointer data)
g_io_channel_set_encoding(cxt->server_io, NULL, NULL);
g_io_channel_set_buffered(cxt->server_io, FALSE);
- cxt->att = g_attrib_new(cxt->att_io, DEFAULT_MTU);
+ cxt->att = g_attrib_new(cxt->att_io, DEFAULT_MTU, false);
g_assert(cxt->att != NULL);
}
diff --git a/unit/test-gdbus-client.c b/unit/test-gdbus-client.c
index ad426fe2..dd17c00f 100644
--- a/unit/test-gdbus-client.c
+++ b/unit/test-gdbus-client.c
@@ -29,12 +29,13 @@
#include "gdbus/gdbus.h"
+#include "src/shared/tester.h"
+
#define SERVICE_NAME "org.bluez.unit.test-gdbus-client"
#define SERVICE_NAME1 "org.bluez.unit.test-gdbus-client1"
#define SERVICE_PATH "/org/bluez/unit/test_gdbus_client"
struct context {
- GMainLoop *main_loop;
DBusConnection *dbus_conn;
GDBusClient *dbus_client;
GDBusProxy *proxy;
@@ -60,26 +61,18 @@ static struct context *create_context(void)
struct context *context = g_new0(struct context, 1);
DBusError err;
- context->main_loop = g_main_loop_new(NULL, FALSE);
- if (context->main_loop == NULL) {
- g_free(context);
- return NULL;
- }
-
dbus_error_init(&err);
context->dbus_conn = g_dbus_setup_private(DBUS_BUS_SESSION,
SERVICE_NAME, &err);
if (context->dbus_conn == NULL) {
if (dbus_error_is_set(&err)) {
- if (g_test_verbose())
- g_printerr("D-Bus setup failed: %s\n",
- err.message);
+ tester_debug("D-Bus setup failed: %s", err.message);
dbus_error_free(&err);
}
- g_main_loop_unref(context->main_loop);
g_free(context);
+ tester_test_abort();
return NULL;
}
@@ -97,17 +90,20 @@ static void destroy_context(struct context *context)
if (context == NULL)
return;
+ tester_test_passed();
+
if (context->timeout_source > 0)
g_source_remove(context->timeout_source);
g_dbus_detach_object_manager(context->dbus_conn);
+ g_dbus_unregister_interface(context->dbus_conn,
+ SERVICE_PATH, SERVICE_NAME);
+
dbus_connection_flush(context->dbus_conn);
dbus_connection_close(context->dbus_conn);
dbus_connection_unref(context->dbus_conn);
- g_main_loop_unref(context->main_loop);
-
g_free(context->data);
g_free(context);
}
@@ -116,8 +112,7 @@ static gboolean timeout_handler(gpointer user_data)
{
struct context *context = user_data;
- if (g_test_verbose())
- g_print("timeout triggered\n");
+ tester_debug("timeout triggered");
context->timeout_source = 0;
@@ -130,8 +125,7 @@ static void connect_handler(DBusConnection *connection, void *user_data)
{
struct context *context = user_data;
- if (g_test_verbose())
- g_print("service connected\n");
+ tester_debug("service connected");
g_dbus_client_unref(context->dbus_client);
}
@@ -140,13 +134,12 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
{
struct context *context = user_data;
- if (g_test_verbose())
- g_print("service disconnected\n");
+ tester_debug("service disconnected");
- g_main_loop_quit(context->main_loop);
+ destroy_context(context);
}
-static void simple_client(void)
+static void simple_client(const void *data)
{
struct context *context = create_context();
@@ -160,13 +153,9 @@ static void simple_client(void)
connect_handler, context);
g_dbus_client_set_disconnect_watch(context->dbus_client,
disconnect_handler, context);
-
- g_main_loop_run(context->main_loop);
-
- destroy_context(context);
}
-static void client_connect_disconnect(void)
+static void client_connect_disconnect(const void *data)
{
struct context *context = create_context();
@@ -187,13 +176,6 @@ static void client_connect_disconnect(void)
context->timeout_source = g_timeout_add_seconds(10, timeout_handler,
context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void append_variant(DBusMessageIter *iter, int type, void *val)
@@ -256,9 +238,7 @@ static void proxy_get_dict(GDBusProxy *proxy, void *user_data)
const char *string;
dbus_bool_t boolean;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_get_property(proxy, "Dict", &iter));
g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);
@@ -307,7 +287,7 @@ static void proxy_get_dict(GDBusProxy *proxy, void *user_data)
g_dbus_client_unref(context->dbus_client);
}
-static void client_get_dict_property(void)
+static void client_get_dict_property(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable dict_properties[] = {
@@ -330,13 +310,6 @@ static void client_get_dict_property(void)
disconnect_handler, context);
g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_dict,
NULL, NULL, context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void proxy_get_string(GDBusProxy *proxy, void *user_data)
@@ -345,13 +318,16 @@ static void proxy_get_string(GDBusProxy *proxy, void *user_data)
DBusMessageIter iter;
const char *string;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_get_property(proxy, "String", &iter));
g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
+ if (context->proxy) {
+ g_assert(context->proxy == proxy);
+ g_dbus_proxy_unref(context->proxy);
+ }
+
dbus_message_iter_get_basic(&iter, &string);
g_assert_cmpstr(string, ==, "value");
@@ -368,7 +344,7 @@ static gboolean get_string(const GDBusPropertyTable *property,
return TRUE;
}
-static void client_get_string_property(void)
+static void client_get_string_property(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable string_properties[] = {
@@ -392,13 +368,6 @@ static void client_get_string_property(void)
disconnect_handler, context);
g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_string,
NULL, NULL, context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void proxy_get_boolean(GDBusProxy *proxy, void *user_data)
@@ -407,9 +376,7 @@ static void proxy_get_boolean(GDBusProxy *proxy, void *user_data)
DBusMessageIter iter;
dbus_bool_t value;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_get_property(proxy, "Boolean", &iter));
g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BOOLEAN);
@@ -430,7 +397,7 @@ static gboolean get_boolean(const GDBusPropertyTable *property,
return TRUE;
}
-static void client_get_boolean_property(void)
+static void client_get_boolean_property(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable boolean_properties[] = {
@@ -454,13 +421,6 @@ static void client_get_boolean_property(void)
NULL, NULL, context);
g_dbus_client_set_disconnect_watch(context->dbus_client,
disconnect_handler, context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void proxy_get_array(GDBusProxy *proxy, void *user_data)
@@ -469,9 +429,7 @@ static void proxy_get_array(GDBusProxy *proxy, void *user_data)
DBusMessageIter iter, entry;
const char *value1, *value2;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_get_property(proxy, "Array", &iter));
g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);
@@ -507,7 +465,7 @@ static gboolean get_array(const GDBusPropertyTable *property,
return TRUE;
}
-static void client_get_array_property(void)
+static void client_get_array_property(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable array_properties[] = {
@@ -530,13 +488,6 @@ static void client_get_array_property(void)
NULL, NULL, context);
g_dbus_client_set_disconnect_watch(context->dbus_client,
disconnect_handler, context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void proxy_get_uint64(GDBusProxy *proxy, void *user_data)
@@ -545,9 +496,7 @@ static void proxy_get_uint64(GDBusProxy *proxy, void *user_data)
DBusMessageIter iter;
guint64 value;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_get_property(proxy, "Number", &iter));
g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT64);
@@ -568,7 +517,7 @@ static gboolean get_uint64(const GDBusPropertyTable *property,
return TRUE;
}
-static void client_get_uint64_property(void)
+static void client_get_uint64_property(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable uint64_properties[] = {
@@ -592,13 +541,6 @@ static void client_get_uint64_property(void)
NULL, NULL, context);
g_dbus_client_set_disconnect_watch(context->dbus_client,
disconnect_handler, context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void property_set_success(const DBusError *err, void *user_data)
@@ -611,9 +553,7 @@ static void proxy_set_string(GDBusProxy *proxy, void *user_data)
DBusMessageIter iter;
const char *string;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_get_property(proxy, "String", &iter));
g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
@@ -634,8 +574,7 @@ static void property_string_changed(GDBusProxy *proxy, const char *name,
struct context *context = user_data;
const char *string;
- if (g_test_verbose())
- g_print("property %s changed\n", name);
+ tester_debug("property %s changed", name);
g_assert(g_strcmp0(name, "String") == 0);
g_assert(dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING);
@@ -667,7 +606,7 @@ static void set_string(const GDBusPropertyTable *property,
g_dbus_pending_property_success(id);
}
-static void client_set_string_property(void)
+static void client_set_string_property(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable string_properties[] = {
@@ -692,13 +631,6 @@ static void client_set_string_property(void)
g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_set_string,
NULL, property_string_changed,
context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static gboolean string_exists(const GDBusPropertyTable *property, void *data)
@@ -712,8 +644,7 @@ static gboolean timeout_test(gpointer user_data)
{
struct context *context = user_data;
- if (g_test_verbose())
- g_print("timeout triggered\n");
+ tester_debug("timeout triggered");
context->timeout_source = 0;
@@ -742,16 +673,14 @@ static void proxy_string_changed(GDBusProxy *proxy, void *user_data)
struct context *context = user_data;
DBusMessageIter iter;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(!g_dbus_proxy_get_property(proxy, "String", &iter));
g_idle_add(emit_string_change, context);
}
-static void client_string_changed(void)
+static void client_string_changed(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable string_properties[] = {
@@ -776,13 +705,6 @@ static void client_string_changed(void)
proxy_string_changed, NULL,
property_string_changed,
context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void property_check_order(const DBusError *err, void *user_data)
@@ -807,9 +729,7 @@ static void proxy_check_order(GDBusProxy *proxy, void *user_data)
struct context *context = user_data;
const char *string;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
context->proxy = proxy;
string = "value1";
@@ -819,7 +739,7 @@ static void proxy_check_order(GDBusProxy *proxy, void *user_data)
NULL));
}
-static void client_check_order(void)
+static void client_check_order(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable string_properties[] = {
@@ -844,32 +764,22 @@ static void client_check_order(void)
g_dbus_client_set_proxy_handlers(context->dbus_client,
proxy_check_order, NULL, NULL,
context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(context->dbus_conn,
- SERVICE_PATH, SERVICE_NAME);
-
- destroy_context(context);
}
static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
struct context *context = user_data;
- if (g_test_verbose())
- g_print("proxy removed\n");
+ tester_debug("proxy removed");
- g_main_loop_quit(context->main_loop);
+ destroy_context(context);
}
static void proxy_set_removed(GDBusProxy *proxy, void *user_data)
{
struct context *context = user_data;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_set_removed_watch(proxy, proxy_removed, context));
@@ -880,7 +790,7 @@ static void proxy_set_removed(GDBusProxy *proxy, void *user_data)
SERVICE_NAME);
}
-static void client_proxy_removed(void)
+static void client_proxy_removed(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable string_properties[] = {
@@ -902,16 +812,11 @@ static void client_proxy_removed(void)
g_dbus_client_set_proxy_handlers(context->dbus_client,
proxy_set_removed, NULL, NULL,
context);
-
- g_main_loop_run(context->main_loop);
-
- destroy_context(context);
}
-static void client_no_object_manager(void)
+static void client_no_object_manager(const void *data)
{
struct context *context = create_context();
- DBusConnection *conn;
DBusMessageIter iter;
static const GDBusPropertyTable string_properties[] = {
{ "String", "s", get_string, set_string, string_exists },
@@ -921,41 +826,27 @@ static void client_no_object_manager(void)
if (context == NULL)
return;
- conn = g_dbus_setup_private(DBUS_BUS_SESSION, SERVICE_NAME1, NULL);
- g_assert(conn != NULL);
-
context->data = g_strdup("value");
- g_dbus_register_interface(conn,
- SERVICE_PATH, SERVICE_NAME1,
+ g_dbus_register_interface(context->dbus_conn,
+ SERVICE_PATH, SERVICE_NAME,
methods, signals, string_properties,
context, NULL);
context->dbus_client = g_dbus_client_new_full(context->dbus_conn,
- SERVICE_NAME1, SERVICE_PATH,
+ SERVICE_NAME, SERVICE_PATH,
NULL);
g_dbus_client_set_disconnect_watch(context->dbus_client,
disconnect_handler, context);
context->proxy = g_dbus_proxy_new(context->dbus_client, SERVICE_PATH,
- SERVICE_NAME1);
+ SERVICE_NAME);
g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_string,
NULL, NULL, context);
g_assert(!g_dbus_proxy_get_property(context->proxy, "String", &iter));
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_proxy_unref(context->proxy);
- g_dbus_unregister_interface(conn, SERVICE_PATH, SERVICE_NAME1);
-
- dbus_connection_flush(conn);
- dbus_connection_close(conn);
- dbus_connection_unref(conn);
-
- destroy_context(context);
}
static void proxy_force_disconnect(GDBusProxy *proxy, void *user_data)
@@ -963,21 +854,24 @@ static void proxy_force_disconnect(GDBusProxy *proxy, void *user_data)
struct context *context = user_data;
DBusConnection *conn = context->data;
- if (g_test_verbose())
- g_print("proxy %s found\n",
- g_dbus_proxy_get_interface(proxy));
+ tester_debug("proxy %s found", g_dbus_proxy_get_interface(proxy));
g_assert(g_dbus_proxy_set_removed_watch(proxy, proxy_removed, context));
context->timeout_source = g_timeout_add_seconds(2, timeout_test,
context);
+ g_dbus_detach_object_manager(conn);
+
+ g_dbus_unregister_interface(conn, SERVICE_PATH, SERVICE_NAME1);
+
dbus_connection_flush(conn);
dbus_connection_close(conn);
+ dbus_connection_unref(conn);
context->data = NULL;
}
-static void client_force_disconnect(void)
+static void client_force_disconnect(const void *data)
{
struct context *context = create_context();
DBusConnection *conn;
@@ -1007,14 +901,6 @@ static void client_force_disconnect(void)
g_dbus_client_set_proxy_handlers(context->dbus_client,
proxy_force_disconnect, NULL, NULL,
context);
-
- g_main_loop_run(context->main_loop);
-
- g_dbus_unregister_interface(conn, SERVICE_PATH, SERVICE_NAME1);
- g_dbus_detach_object_manager(conn);
- dbus_connection_unref(conn);
-
- destroy_context(context);
}
static void client_ready_watch(GDBusClient *client, void *user_data)
@@ -1035,10 +921,10 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
*/
g_assert(context->client_ready == FALSE);
- g_main_loop_quit(context->main_loop);
+ destroy_context(context);
}
-static void client_ready(void)
+static void client_ready(const void *data)
{
struct context *context = create_context();
static const GDBusPropertyTable string_properties[] = {
@@ -1061,53 +947,51 @@ static void client_ready(void)
context);
g_dbus_client_set_proxy_handlers(context->dbus_client,
proxy_added, NULL, NULL, context);
-
- g_main_loop_run(context->main_loop);
-
- destroy_context(context);
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- g_test_add_func("/gdbus/simple_client", simple_client);
+ tester_add("/gdbus/simple_client", NULL, NULL, simple_client, NULL);
- g_test_add_func("/gdbus/client_connect_disconnect",
- client_connect_disconnect);
+ tester_add("/gdbus/client_connect_disconnect", NULL, NULL,
+ client_connect_disconnect, NULL);
- g_test_add_func("/gdbus/client_get_string_property",
- client_get_string_property);
+ tester_add("/gdbus/client_get_string_property", NULL, NULL,
+ client_get_string_property, NULL);
- g_test_add_func("/gdbus/client_get_boolean_property",
- client_get_boolean_property);
+ tester_add("/gdbus/client_get_boolean_property", NULL, NULL,
+ client_get_boolean_property, NULL);
- g_test_add_func("/gdbus/client_get_uint64_property",
- client_get_uint64_property);
+ tester_add("/gdbus/client_get_uint64_property", NULL, NULL,
+ client_get_uint64_property, NULL);
- g_test_add_func("/gdbus/client_get_array_property",
- client_get_array_property);
+ tester_add("/gdbus/client_get_array_property", NULL, NULL,
+ client_get_array_property, NULL);
- g_test_add_func("/gdbus/client_get_dict_property",
- client_get_dict_property);
+ tester_add("/gdbus/client_get_dict_property", NULL, NULL,
+ client_get_dict_property, NULL);
- g_test_add_func("/gdbus/client_set_string_property",
- client_set_string_property);
+ tester_add("/gdbus/client_set_string_property", NULL, NULL,
+ client_set_string_property, NULL);
- g_test_add_func("/gdbus/client_string_changed",
- client_string_changed);
+ tester_add("/gdbus/client_string_changed", NULL, NULL,
+ client_string_changed, NULL);
- g_test_add_func("/gdbus/client_check_order", client_check_order);
+ tester_add("/gdbus/client_check_order", NULL, NULL, client_check_order,
+ NULL);
- g_test_add_func("/gdbus/client_proxy_removed", client_proxy_removed);
+ tester_add("/gdbus/client_proxy_removed", NULL, NULL,
+ client_proxy_removed, NULL);
- g_test_add_func("/gdbus/client_no_object_manager",
- client_no_object_manager);
+ tester_add("/gdbus/client_no_object_manager", NULL, NULL,
+ client_no_object_manager, NULL);
- g_test_add_func("/gdbus/client_force_disconnect",
- client_force_disconnect);
+ tester_add("/gdbus/client_force_disconnect", NULL, NULL,
+ client_force_disconnect, NULL);
- g_test_add_func("/gdbus/client_ready", client_ready);
+ tester_add("/gdbus/client_ready", NULL, NULL, client_ready, NULL);
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-gobex-header.c b/unit/test-gobex-header.c
index 6f493125..8705892c 100644
--- a/unit/test-gobex-header.c
+++ b/unit/test-gobex-header.c
@@ -554,7 +554,7 @@ int main(int argc, char *argv[])
test_header_encode_name_umlaut);
g_test_add_func("/gobex/test_header_encode_body",
test_header_encode_body);
- g_test_add_func("/gobex/test_header_encode_connid",
+ g_test_add_func("/gobex/test_header_encode_actionid",
test_header_encode_actionid);
g_test_add_func("/gobex/test_header_encode_apparam",
test_header_encode_apparam);
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 66966ce5..f2b9622c 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -29,9 +29,9 @@
#include <glib.h>
#include "src/shared/hfp.h"
+#include "src/shared/tester.h"
struct context {
- GMainLoop *main_loop;
guint watch_id;
int fd_server;
int fd_client;
@@ -97,7 +97,7 @@ struct test_data {
data.test_name = g_strdup(name); \
data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
data.result_func = result_function; \
- g_test_add_data_func(name, &data, function); \
+ tester_add(name, &data, NULL, function, NULL); \
data.test_handler = test_handler; \
} while (0)
@@ -112,15 +112,10 @@ struct test_data {
data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
data.hf_result_func = result_func; \
data.response_func = response_function; \
- g_test_add_data_func(name, &data, function); \
+ tester_add(name, &data, NULL, function, NULL); \
data.test_handler = test_hf_handler; \
} while (0)
-static void context_quit(struct context *context)
-{
- g_main_loop_quit(context->main_loop);
-}
-
static void test_free(gconstpointer user_data)
{
const struct test_data *data = user_data;
@@ -129,6 +124,34 @@ static void test_free(gconstpointer user_data)
g_free(data->pdu_list);
}
+static void destroy_context(struct context *context)
+{
+ if (context->watch_id)
+ g_source_remove(context->watch_id);
+
+ test_free(context->data);
+
+ if (context->hfp)
+ hfp_gw_unref(context->hfp);
+
+ if (context->hfp_hf)
+ hfp_hf_unref(context->hfp_hf);
+
+ g_free(context);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+ struct context *context = user_data;
+
+ if (context == NULL)
+ return FALSE;
+
+ destroy_context(context);
+ tester_test_passed();
+ return FALSE;
+}
+
static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
gpointer user_data)
{
@@ -138,10 +161,10 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
pdu = &context->data->pdu_list[context->pdu_offset++];
g_assert(!pdu->valid);
- context_quit(context);
-
context->watch_id = 0;
+ context_quit(context);
+
return FALSE;
}
@@ -184,9 +207,10 @@ static gboolean test_hf_handler(GIOChannel *channel, GIOCondition cond,
return TRUE;
done:
- context_quit(context);
context->watch_id = 0;
+ context_quit(context);
+
return FALSE;
}
@@ -224,9 +248,6 @@ static struct context *create_context(gconstpointer data)
int err, sv[2];
const struct test_data *d = data;
- context->main_loop = g_main_loop_new(NULL, FALSE);
- g_assert(context->main_loop);
-
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
g_assert(err == 0);
@@ -251,26 +272,6 @@ static struct context *create_context(gconstpointer data)
return context;
}
-static void execute_context(struct context *context)
-{
- g_main_loop_run(context->main_loop);
-
- if (context->watch_id)
- g_source_remove(context->watch_id);
-
- g_main_loop_unref(context->main_loop);
-
- test_free(context->data);
-
- if (context->hfp)
- hfp_gw_unref(context->hfp);
-
- if (context->hfp_hf)
- hfp_hf_unref(context->hfp_hf);
-
- g_free(context);
-}
-
static void test_init(gconstpointer data)
{
struct context *context = create_context(data);
@@ -283,7 +284,7 @@ static void test_init(gconstpointer data)
hfp_gw_unref(context->hfp);
context->hfp = NULL;
- execute_context(context);
+ context_quit(context);
}
static void test_command_handler(gconstpointer data)
@@ -308,7 +309,7 @@ static void test_command_handler(gconstpointer data)
len = write(context->fd_server, pdu->data, pdu->size);
g_assert_cmpint(len, ==, pdu->size);
- execute_context(context);
+ context_quit(context);
}
static void test_register(gconstpointer data)
@@ -337,7 +338,7 @@ static void test_register(gconstpointer data)
len = write(context->fd_server, pdu->data, pdu->size);
g_assert_cmpint(len, ==, pdu->size);
- execute_context(context);
+ context_quit(context);
}
static void test_fragmented(gconstpointer data)
@@ -352,8 +353,6 @@ static void test_fragmented(gconstpointer data)
g_assert(ret);
g_idle_add(send_pdu, context);
-
- execute_context(context);
}
static void test_send_and_close(gconstpointer data)
@@ -372,7 +371,7 @@ static void test_send_and_close(gconstpointer data)
hfp_gw_unref(context->hfp);
context->hfp = NULL;
- execute_context(context);
+ context_quit(context);
}
static void check_ustring_1(struct hfp_context *result,
@@ -494,7 +493,7 @@ static void test_hf_init(gconstpointer data)
hfp_hf_unref(context->hfp_hf);
context->hfp_hf = NULL;
- execute_context(context);
+ context_quit(context);
}
static bool unsolicited_resp = false;
@@ -567,7 +566,7 @@ static void test_hf_send_command(gconstpointer data)
g_assert(ret);
}
- execute_context(context);
+ context_quit(context);
}
static void hf_chld_result_handler(struct hfp_context *hf_context,
void *user_data)
@@ -667,8 +666,6 @@ static void test_hf_unsolicited(gconstpointer data)
}
send_pdu(context);
-
- execute_context(context);
}
static void test_hf_robustness(gconstpointer data)
@@ -687,12 +684,12 @@ static void test_hf_robustness(gconstpointer data)
hfp_hf_unref(context->hfp_hf);
context->hfp_hf = NULL;
- execute_context(context);
+ context_quit(context);
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
define_test("/hfp/test_init", test_init, NULL, data_end());
define_test("/hfp/test_cmd_handler_1", test_command_handler, NULL,
@@ -860,5 +857,5 @@ int main(int argc, char *argv[])
frg_pdu('1', ',', '2', 'x', '\r', '\n'),
data_end());
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-hog.c b/unit/test-hog.c
index 778f0879..9f026e59 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -37,7 +37,7 @@
#include "attrib/gattrib.h"
-#include "android/hog.h"
+#include "profiles/input/hog-lib.h"
struct test_pdu {
bool valid;
@@ -187,7 +187,7 @@ static struct context *create_context(gconstpointer data)
g_io_channel_set_close_on_unref(att_io, TRUE);
- context->attrib = g_attrib_new(att_io, 23);
+ context->attrib = g_attrib_new(att_io, 23, false);
g_assert(context->attrib);
g_io_channel_unref(att_io);
diff --git a/unit/test-lib.c b/unit/test-lib.c
index ef0cffc5..bd4c5eec 100644
--- a/unit/test-lib.c
+++ b/unit/test-lib.c
@@ -31,27 +31,30 @@
#include <errno.h>
#include "src/shared/util.h"
+#include "src/shared/tester.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
-static void test_ntoh64(void)
+static void test_ntoh64(const void *data)
{
uint64_t test = 0x123456789abcdef;
g_assert(ntoh64(test) == be64toh(test));
g_assert(ntoh64(test) == be64_to_cpu(test));
+ tester_test_passed();
}
-static void test_hton64(void)
+static void test_hton64(const void *data)
{
uint64_t test = 0x123456789abcdef;
g_assert(hton64(test) == htobe64(test));
g_assert(hton64(test) == cpu_to_be64(test));
+ tester_test_passed();
}
-static void test_sdp_get_access_protos_valid(void)
+static void test_sdp_get_access_protos_valid(const void *data)
{
sdp_record_t *rec;
sdp_list_t *aproto, *apseq, *proto[2];
@@ -91,9 +94,10 @@ static void test_sdp_get_access_protos_valid(void)
sdp_list_free(aproto, NULL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_access_protos_nodata(void)
+static void test_sdp_get_access_protos_nodata(const void *data)
{
sdp_record_t *rec;
sdp_list_t *aproto;
@@ -108,9 +112,10 @@ static void test_sdp_get_access_protos_nodata(void)
g_assert(err == -1 && errno == ENODATA);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_access_protos_invalid_dtd1(void)
+static void test_sdp_get_access_protos_invalid_dtd1(const void *tdata)
{
const uint32_t u32 = 0xdeadbeeb;
sdp_record_t *rec;
@@ -135,9 +140,10 @@ static void test_sdp_get_access_protos_invalid_dtd1(void)
g_assert(err == -1 && errno == EINVAL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_access_protos_invalid_dtd2(void)
+static void test_sdp_get_access_protos_invalid_dtd2(const void *tdata)
{
uint8_t dtd = SDP_UINT8, u8 = 0xff;
void *dtds = &dtd, *values = &u8;
@@ -163,9 +169,10 @@ static void test_sdp_get_access_protos_invalid_dtd2(void)
g_assert(err == -1 && errno == EINVAL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_lang_attr_valid(void)
+static void test_sdp_get_lang_attr_valid(const void *data)
{
sdp_record_t *rec;
sdp_list_t *list;
@@ -179,9 +186,10 @@ static void test_sdp_get_lang_attr_valid(void)
sdp_list_free(list, free);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_lang_attr_nodata(void)
+static void test_sdp_get_lang_attr_nodata(const void *data)
{
sdp_record_t *rec;
sdp_list_t *list;
@@ -193,9 +201,10 @@ static void test_sdp_get_lang_attr_nodata(void)
g_assert(err == -1 && errno == ENODATA);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_lang_attr_invalid_dtd(void)
+static void test_sdp_get_lang_attr_invalid_dtd(const void *tdata)
{
uint8_t dtd1 = SDP_UINT16, dtd2 = SDP_UINT32;
uint32_t u32 = 0xdeadbeeb;
@@ -243,9 +252,10 @@ static void test_sdp_get_lang_attr_invalid_dtd(void)
g_assert(err == -1 && errno == EINVAL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_profile_descs_valid(void)
+static void test_sdp_get_profile_descs_valid(const void *data)
{
sdp_profile_desc_t profile;
sdp_record_t *rec;
@@ -267,9 +277,10 @@ static void test_sdp_get_profile_descs_valid(void)
g_assert(err == 0 && list != NULL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_profile_descs_nodata(void)
+static void test_sdp_get_profile_descs_nodata(const void *data)
{
sdp_record_t *rec;
sdp_list_t *list;
@@ -281,9 +292,10 @@ static void test_sdp_get_profile_descs_nodata(void)
g_assert(err == -1 && errno == ENODATA);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_profile_descs_invalid_dtd(void)
+static void test_sdp_get_profile_descs_invalid_dtd(const void *tdata)
{
uint8_t dtd1 = SDP_UUID16, dtd2 = SDP_UINT32;
uint32_t u32 = 0xdeadbeeb;
@@ -354,9 +366,10 @@ static void test_sdp_get_profile_descs_invalid_dtd(void)
g_assert(err == -1 && errno == EINVAL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_profile_descs_workaround(void)
+static void test_sdp_get_profile_descs_workaround(const void *tdata)
{
uint8_t dtd1 = SDP_UUID16, dtd2 = SDP_UINT16, dtd3 = SDP_UINT32;
uint16_t u16 = 0x1234;
@@ -404,9 +417,10 @@ static void test_sdp_get_profile_descs_workaround(void)
g_assert(err == -1 && errno == EINVAL);
sdp_record_free(rec);
+ tester_test_passed();
}
-static void test_sdp_get_server_ver(void)
+static void test_sdp_get_server_ver(const void *tdata)
{
uint16_t u16 = 0x1234;
uint32_t u32 = 0xdeadbeeb;
@@ -451,42 +465,44 @@ static void test_sdp_get_server_ver(void)
g_assert(err == -1 && errno == EINVAL);
sdp_record_free(rec);
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/lib/ntoh64", test_ntoh64);
- g_test_add_func("/lib/hton64", test_hton64);
-
- g_test_add_func("/lib/sdp_get_access_protos/valid",
- test_sdp_get_access_protos_valid);
- g_test_add_func("/lib/sdp_get_access_protos/nodata",
- test_sdp_get_access_protos_nodata);
- g_test_add_func("/lib/sdp_get_access_protos/invalid_dtd1",
- test_sdp_get_access_protos_invalid_dtd1);
- g_test_add_func("/lib/sdp_get_access_protos/invalid_dtd2",
- test_sdp_get_access_protos_invalid_dtd2);
-
- g_test_add_func("/lib/sdp_get_lang_attr/valid",
- test_sdp_get_lang_attr_valid);
- g_test_add_func("/lib/sdp_get_lang_attr/nodata",
- test_sdp_get_lang_attr_nodata);
- g_test_add_func("/lib/sdp_get_lang_attr/invalid_dtd",
- test_sdp_get_lang_attr_invalid_dtd);
-
- g_test_add_func("/lib/sdp_get_profile_descs/valid",
- test_sdp_get_profile_descs_valid);
- g_test_add_func("/lib/sdp_get_profile_descs/nodata",
- test_sdp_get_profile_descs_nodata);
- g_test_add_func("/lib/sdp_get_profile_descs/invalid_dtd",
- test_sdp_get_profile_descs_invalid_dtd);
+ tester_init(&argc, &argv);
+
+ tester_add("/lib/ntoh64", NULL, NULL, test_ntoh64, NULL);
+ tester_add("/lib/hton64", NULL, NULL, test_hton64, NULL);
+
+ tester_add("/lib/sdp_get_access_protos/valid", NULL, NULL,
+ test_sdp_get_access_protos_valid, NULL);
+ tester_add("/lib/sdp_get_access_protos/nodata", NULL, NULL,
+ test_sdp_get_access_protos_nodata, NULL);
+ tester_add("/lib/sdp_get_access_protos/invalid_dtd1", NULL, NULL,
+ test_sdp_get_access_protos_invalid_dtd1, NULL);
+ tester_add("/lib/sdp_get_access_protos/invalid_dtd2", NULL, NULL,
+ test_sdp_get_access_protos_invalid_dtd2, NULL);
+
+ tester_add("/lib/sdp_get_lang_attr/valid", NULL, NULL,
+ test_sdp_get_lang_attr_valid, NULL);
+ tester_add("/lib/sdp_get_lang_attr/nodata", NULL, NULL,
+ test_sdp_get_lang_attr_nodata, NULL);
+ tester_add("/lib/sdp_get_lang_attr/invalid_dtd", NULL, NULL,
+ test_sdp_get_lang_attr_invalid_dtd, NULL);
+
+ tester_add("/lib/sdp_get_profile_descs/valid", NULL, NULL,
+ test_sdp_get_profile_descs_valid, NULL);
+ tester_add("/lib/sdp_get_profile_descs/nodata", NULL, NULL,
+ test_sdp_get_profile_descs_nodata, NULL);
+ tester_add("/lib/sdp_get_profile_descs/invalid_dtd", NULL, NULL,
+ test_sdp_get_profile_descs_invalid_dtd, NULL);
/* Test for workaround commented on sdp_get_profile_descs() */
- g_test_add_func("/lib/sdp_get_profile_descs/workaround",
- test_sdp_get_profile_descs_workaround);
+ tester_add("/lib/sdp_get_profile_descs/workaround", NULL, NULL,
+ test_sdp_get_profile_descs_workaround, NULL);
- g_test_add_func("/lib/sdp_get_server_ver", test_sdp_get_server_ver);
+ tester_add("/lib/sdp_get_server_ver", NULL, NULL,
+ test_sdp_get_server_ver, NULL);
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-queue.c b/unit/test-queue.c
index 12319b01..d912a641 100644
--- a/unit/test-queue.c
+++ b/unit/test-queue.c
@@ -29,8 +29,9 @@
#include "src/shared/util.h"
#include "src/shared/queue.h"
+#include "src/shared/tester.h"
-static void test_basic(void)
+static void test_basic(const void *data)
{
struct queue *queue;
unsigned int n, i;
@@ -56,6 +57,7 @@ static void test_basic(void)
}
queue_destroy(queue, NULL);
+ tester_test_passed();
}
static void foreach_destroy(void *data, void *user_data)
@@ -65,7 +67,7 @@ static void foreach_destroy(void *data, void *user_data)
queue_destroy(queue, NULL);
}
-static void test_foreach_destroy(void)
+static void test_foreach_destroy(const void *data)
{
struct queue *queue;
@@ -76,6 +78,7 @@ static void test_foreach_destroy(void)
queue_push_tail(queue, UINT_TO_PTR(2));
queue_foreach(queue, foreach_destroy, queue);
+ tester_test_passed();
}
static void foreach_remove(void *data, void *user_data)
@@ -85,7 +88,7 @@ static void foreach_remove(void *data, void *user_data)
g_assert(queue_remove(queue, data));
}
-static void test_foreach_remove(void)
+static void test_foreach_remove(const void *data)
{
struct queue *queue;
@@ -97,6 +100,7 @@ static void test_foreach_remove(void)
queue_foreach(queue, foreach_remove, queue);
queue_destroy(queue, NULL);
+ tester_test_passed();
}
static void foreach_remove_all(void *data, void *user_data)
@@ -106,7 +110,7 @@ static void foreach_remove_all(void *data, void *user_data)
queue_remove_all(queue, NULL, NULL, NULL);
}
-static void test_foreach_remove_all(void)
+static void test_foreach_remove_all(const void *data)
{
struct queue *queue;
@@ -118,6 +122,7 @@ static void test_foreach_remove_all(void)
queue_foreach(queue, foreach_remove_all, queue);
queue_destroy(queue, NULL);
+ tester_test_passed();
}
static void foreach_remove_backward(void *data, void *user_data)
@@ -128,7 +133,7 @@ static void foreach_remove_backward(void *data, void *user_data)
queue_remove(queue, UINT_TO_PTR(1));
}
-static void test_foreach_remove_backward(void)
+static void test_foreach_remove_backward(const void *data)
{
struct queue *queue;
@@ -140,6 +145,7 @@ static void test_foreach_remove_backward(void)
queue_foreach(queue, foreach_remove_backward, queue);
queue_destroy(queue, NULL);
+ tester_test_passed();
}
static struct queue *static_queue;
@@ -149,7 +155,7 @@ static void destroy_remove(void *user_data)
queue_remove(static_queue, user_data);
}
-static void test_destroy_remove(void)
+static void test_destroy_remove(const void *data)
{
static_queue = queue_new();
@@ -159,9 +165,10 @@ static void test_destroy_remove(void)
queue_push_tail(static_queue, UINT_TO_PTR(2));
queue_destroy(static_queue, destroy_remove);
+ tester_test_passed();
}
-static void test_push_after(void)
+static void test_push_after(const void *data)
{
struct queue *queue;
unsigned int len, i;
@@ -212,6 +219,7 @@ static void test_push_after(void)
g_assert(queue_pop_head(queue) == UINT_TO_PTR(1));
queue_destroy(queue, NULL);
+ tester_test_passed();
}
static bool match_int(const void *a, const void *b)
@@ -227,7 +235,7 @@ static bool match_ptr(const void *a, const void *b)
return a == b;
}
-static void test_remove_all(void)
+static void test_remove_all(const void *data)
{
struct queue *queue;
@@ -248,21 +256,26 @@ static void test_remove_all(void)
g_assert(queue_isempty(queue));
queue_destroy(queue, NULL);
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/queue/basic", test_basic);
- g_test_add_func("/queue/foreach_destroy", test_foreach_destroy);
- g_test_add_func("/queue/foreach_remove", test_foreach_remove);
- g_test_add_func("/queue/foreach_remove_all", test_foreach_remove_all);
- g_test_add_func("/queue/foreach_remove_backward",
- test_foreach_remove_backward);
- g_test_add_func("/queue/destroy_remove", test_destroy_remove);
- g_test_add_func("/queue/push_after", test_push_after);
- g_test_add_func("/queue/remove_all", test_remove_all);
-
- return g_test_run();
+ tester_init(&argc, &argv);
+
+ tester_add("/queue/basic", NULL, NULL, test_basic, NULL);
+ tester_add("/queue/foreach_destroy", NULL, NULL,
+ test_foreach_destroy, NULL);
+ tester_add("/queue/foreach_remove", NULL, NULL,
+ test_foreach_remove, NULL);
+ tester_add("/queue/foreach_remove_all", NULL, NULL,
+ test_foreach_remove_all, NULL);
+ tester_add("/queue/foreach_remove_backward", NULL, NULL,
+ test_foreach_remove_backward, NULL);
+ tester_add("/queue/destroy_remove", NULL, NULL,
+ test_destroy_remove, NULL);
+ tester_add("/queue/push_after", NULL, NULL, test_push_after, NULL);
+ tester_add("/queue/remove_all", NULL, NULL, test_remove_all, NULL);
+
+ return tester_run();
}
diff --git a/unit/test-ringbuf.c b/unit/test-ringbuf.c
index e28e04ba..a97524e4 100644
--- a/unit/test-ringbuf.c
+++ b/unit/test-ringbuf.c
@@ -32,6 +32,7 @@
#include <glib.h>
#include "src/shared/ringbuf.h"
+#include "src/shared/tester.h"
static unsigned int nlpo2(unsigned int x)
{
@@ -54,7 +55,7 @@ static unsigned int align_power2(unsigned int u)
return 1 << fls(u - 1);
}
-static void test_power2(void)
+static void test_power2(const void *data)
{
size_t i;
@@ -68,25 +69,25 @@ static void test_power2(void)
while (size3 < i && size3 < SIZE_MAX)
size3 <<= 1;
- if (g_test_verbose())
- g_print("%zu -> size1=%zu size2=%zu size3=%zu\n",
+ tester_debug("%zu -> size1=%zu size2=%zu size3=%zu\n",
i, size1, size2, size3);
g_assert(size1 == size2);
g_assert(size2 == size3);
g_assert(size3 == size1);
}
+
+ tester_test_passed();
}
-static void test_alloc(void)
+static void test_alloc(const void *data)
{
int i;
for (i = 2; i < 10000; i++) {
struct ringbuf *rb;
- if (g_test_verbose())
- g_print("Iteration %i\n", i);
+ tester_debug("Iteration %i\n", i);
rb = ringbuf_new(i);
g_assert(rb != NULL);
@@ -95,9 +96,11 @@ static void test_alloc(void)
ringbuf_free(rb);
}
+
+ tester_test_passed();
}
-static void test_printf(void)
+static void test_printf(const void *data)
{
static size_t rb_size = 500;
static size_t rb_capa = 512;
@@ -115,8 +118,7 @@ static void test_printf(void)
if (!count)
continue;
- if (g_test_verbose())
- g_print("Iteration %i\n", i);
+ tester_debug("Iteration %i\n", i);
len = asprintf(&str, "%*c", (int) count, 'x');
g_assert(len == count);
@@ -140,15 +142,16 @@ static void test_printf(void)
}
ringbuf_free(rb);
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- g_test_add_func("/ringbuf/power2", test_power2);
- g_test_add_func("/ringbuf/alloc", test_alloc);
- g_test_add_func("/ringbuf/printf", test_printf);
+ tester_add("/ringbuf/power2", NULL, NULL, test_power2, NULL);
+ tester_add("/ringbuf/alloc", NULL, NULL, test_alloc, NULL);
+ tester_add("/ringbuf/printf", NULL, NULL, test_printf, NULL);
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-sdp.c b/unit/test-sdp.c
index b4ef4d1e..ac921a9a 100644
--- a/unit/test-sdp.c
+++ b/unit/test-sdp.c
@@ -37,6 +37,7 @@
#include "lib/sdp_lib.h"
#include "src/shared/util.h"
+#include "src/shared/tester.h"
#include "src/log.h"
#include "src/sdpd.h"
@@ -78,7 +79,7 @@ struct test_data {
static struct test_data data; \
data.mtu = _mtu; \
data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
- g_test_add_data_func(name, &data, test_sdp); \
+ tester_add(name, &data, NULL, test_sdp, NULL); \
} while (0)
#define define_ss(name, args...) define_test("/TP/SERVER/SS/" name, 48, args)
@@ -105,32 +106,48 @@ struct test_data_de {
data.input_data = input; \
data.input_size = sizeof(input); \
data.expected = exp; \
- g_test_add_data_func("/sdp/DE/ATTR/" name, &data, \
- test_sdp_de_attr); \
+ tester_add("/sdp/DE/ATTR/" name, &data, NULL, \
+ test_sdp_de_attr, NULL); \
} while (0)
struct context {
- GMainLoop *main_loop;
guint server_source;
guint client_source;
int fd;
- int mtu;
uint8_t cont_data[16];
uint8_t cont_size;
unsigned int pdu_offset;
- const struct sdp_pdu *pdu_list;
+ const struct test_data *data;
};
static void sdp_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
- g_print("%s%s\n", prefix, str);
+ tester_debug("%s%s\n", prefix, str);
+}
+
+static void destroy_context(struct context *context)
+{
+ sdp_svcdb_collect_all(context->fd);
+ sdp_svcdb_reset();
+
+ g_source_remove(context->server_source);
+ g_source_remove(context->client_source);
+
+ g_free(context);
}
-static void context_quit(struct context *context)
+static gboolean context_quit(gpointer user_data)
{
- g_main_loop_quit(context->main_loop);
+ struct context *context = user_data;
+ if (context == NULL)
+ return FALSE;
+
+ destroy_context(context);
+ tester_test_passed();
+
+ return FALSE;
}
static gboolean server_handler(GIOChannel *channel, GIOCondition cond,
@@ -169,10 +186,9 @@ static gboolean server_handler(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
- if (g_test_verbose() == TRUE)
- util_hexdump('<', buf, len, sdp_debug, "SDP: ");
+ util_hexdump('<', buf, len, sdp_debug, "SDP: ");
- handle_internal_request(fd, context->mtu, buf, len);
+ handle_internal_request(fd, context->data->mtu, buf, len);
return TRUE;
}
@@ -185,7 +201,7 @@ static gboolean send_pdu(gpointer user_data)
unsigned char *buf;
ssize_t len;
- req_pdu = &context->pdu_list[context->pdu_offset];
+ req_pdu = &context->data->pdu_list[context->pdu_offset];
pdu_len = req_pdu->raw_size + context->cont_size;
@@ -210,7 +226,7 @@ static void context_increment(struct context *context)
{
context->pdu_offset += 2;
- if (!context->pdu_list[context->pdu_offset].valid) {
+ if (!context->data->pdu_list[context->pdu_offset].valid) {
context_quit(context);
return;
}
@@ -227,7 +243,7 @@ static gboolean client_handler(GIOChannel *channel, GIOCondition cond,
ssize_t len;
int fd;
- rsp_pdu = &context->pdu_list[context->pdu_offset + 1];
+ rsp_pdu = &context->data->pdu_list[context->pdu_offset + 1];
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
return FALSE;
@@ -238,8 +254,7 @@ static gboolean client_handler(GIOChannel *channel, GIOCondition cond,
if (len < 0)
return FALSE;
- if (g_test_verbose() == TRUE)
- util_hexdump('>', buf, len, sdp_debug, "SDP: ");
+ util_hexdump('>', buf, len, sdp_debug, "SDP: ");
g_assert(len > 0);
g_assert((size_t) len == rsp_pdu->raw_size + rsp_pdu->cont_len);
@@ -638,15 +653,12 @@ static void register_file_transfer(void)
update_db_timestamp();
}
-static struct context *create_context(void)
+static struct context *create_context(gconstpointer data)
{
struct context *context = g_new0(struct context, 1);
GIOChannel *channel;
int err, sv[2];
- context->main_loop = g_main_loop_new(NULL, FALSE);
- g_assert(context->main_loop);
-
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
g_assert(err == 0);
@@ -677,6 +689,7 @@ static struct context *create_context(void)
g_io_channel_unref(channel);
context->fd = sv[1];
+ context->data = data;
set_fixed_db_timestamp(0x496f0654);
@@ -695,34 +708,11 @@ static struct context *create_context(void)
return context;
}
-static void execute_context(struct context *context)
-{
- g_main_loop_run(context->main_loop);
-
- sdp_svcdb_collect_all(context->fd);
- sdp_svcdb_reset();
-
- g_source_remove(context->server_source);
- g_source_remove(context->client_source);
-
- g_main_loop_unref(context->main_loop);
-
- g_free(context);
-}
-
static void test_sdp(gconstpointer data)
{
- const struct test_data *test = data;
- struct context *context = create_context();
-
- context->mtu = test->mtu;
- context->pdu_list = test->pdu_list;
+ struct context *context = create_context(data);
g_idle_add(send_pdu, context);
-
- execute_context(context);
-
- g_free(test->pdu_list);
}
static void test_sdp_de_attr(gconstpointer data)
@@ -737,8 +727,7 @@ static void test_sdp_de_attr(gconstpointer data)
g_assert_cmpuint(test->input_size, ==, size);
g_assert_cmpuint(test->expected.dtd, ==, d->dtd);
- if (g_test_verbose() == TRUE)
- g_print("DTD=0x%02x\n", d->dtd);
+ tester_debug("DTD=0x%02x\n", d->dtd);
switch (d->dtd) {
case SDP_TEXT_STR8:
@@ -785,14 +774,14 @@ static void test_sdp_de_attr(gconstpointer data)
}
sdp_data_free(d);
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- if (g_test_verbose())
- __btd_log_init("*", 0);
+ __btd_log_init("*", 0);
/*
* Service Search Request
@@ -2821,5 +2810,5 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00)));
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-textfile.c b/unit/test-textfile.c
index d873df47..5250f983 100644
--- a/unit/test-textfile.c
+++ b/unit/test-textfile.c
@@ -34,6 +34,7 @@
#include <glib.h>
#include "src/textfile.h"
+#include "src/shared/tester.h"
static const char test_pathname[] = "/tmp/textfile";
@@ -79,7 +80,7 @@ done:
close(fd);
}
-static void test_pagesize(void)
+static void test_pagesize(const void *data)
{
char key[18], *str;
int size;
@@ -87,21 +88,20 @@ static void test_pagesize(void)
size = getpagesize();
g_assert(size >= 4096);
- if (g_test_verbose())
- g_print("System uses a page size of %d bytes\n", size);
+ tester_debug("System uses a page size of %d bytes\n", size);
util_create_pagesize();
sprintf(key, "11:11:11:11:11:11");
str = textfile_get(test_pathname, key);
- if (g_test_verbose())
- g_print("%s\n", str);
+ tester_debug("%s\n", str);
g_assert(str == NULL);
+ tester_test_passed();
}
-static void test_delete(void)
+static void test_delete(const void *data)
{
char key[18], value[512], *str;
@@ -116,13 +116,13 @@ static void test_delete(void)
str = textfile_get(test_pathname, key);
g_assert(str != NULL);
- if (g_test_verbose())
- g_print("%s\n", str);
+ tester_debug("%s\n", str);
g_free(str);
+ tester_test_passed();
}
-static void test_overwrite(void)
+static void test_overwrite(const void *data)
{
char key[18], value[512], *str;
@@ -143,10 +143,10 @@ static void test_overwrite(void)
str = textfile_get(test_pathname, key);
- if (g_test_verbose())
- g_print("%s\n", str);
+ tester_debug("%s\n", str);
g_assert(str == NULL);
+ tester_test_passed();
}
static void check_entry(char *key, char *value, void *data)
@@ -164,7 +164,7 @@ static void check_entry(char *key, char *value, void *data)
g_assert(strlen(value) == len);
}
-static void test_multiple(void)
+static void test_multiple(const void *data)
{
char key[18], value[512], *str;
unsigned int i, j, max = 10;
@@ -182,8 +182,7 @@ static void test_multiple(void)
str = textfile_get(test_pathname, key);
- if (g_test_verbose())
- g_print("%s %s\n", key, str);
+ tester_debug("%s %s\n", key, str);
g_assert(str != NULL);
g_assert(strcmp(str, value) == 0);
@@ -201,8 +200,7 @@ static void test_multiple(void)
str = textfile_get(test_pathname, key);
- if (g_test_verbose())
- g_print("%s %s\n", key, str);
+ tester_debug("%s %s\n", key, str);
g_assert(str != NULL);
g_assert(strcmp(str, value) == 0);
@@ -219,8 +217,7 @@ static void test_multiple(void)
str = textfile_get(test_pathname, key);
- if (g_test_verbose())
- g_print("%s %s\n", key, str);
+ tester_debug("%s %s\n", key, str);
g_assert(str != NULL);
g_assert(strcmp(str, value) == 0);
@@ -231,8 +228,7 @@ static void test_multiple(void)
sprintf(key, "00:00:00:00:00:%02X", i);
str = textfile_get(test_pathname, key);
- if (g_test_verbose())
- g_print("%s %s\n", key, str);
+ tester_debug("%s %s\n", key, str);
g_assert(str != NULL);
@@ -262,16 +258,17 @@ static void test_multiple(void)
g_assert(textfile_del(test_pathname, key) == 0);
textfile_foreach(test_pathname, check_entry, GUINT_TO_POINTER(max));
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- g_test_add_func("/textfile/pagesize", test_pagesize);
- g_test_add_func("/textfile/delete", test_delete);
- g_test_add_func("/textfile/overwrite", test_overwrite);
- g_test_add_func("/textfile/multiple", test_multiple);
+ tester_add("/textfile/pagesize", NULL, NULL, test_pagesize, NULL);
+ tester_add("/textfile/delete", NULL, NULL, test_delete, NULL);
+ tester_add("/textfile/overwrite", NULL, NULL, test_overwrite, NULL);
+ tester_add("/textfile/multiple", NULL, NULL, test_multiple, NULL);
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-uhid.c b/unit/test-uhid.c
index b48e0faa..320cd54d 100644
--- a/unit/test-uhid.c
+++ b/unit/test-uhid.c
@@ -38,6 +38,8 @@
#include "src/shared/uhid.h"
#include "src/shared/util.h"
+#include "src/shared/tester.h"
+
struct test_pdu {
bool valid;
const uint8_t *data;
@@ -50,7 +52,6 @@ struct test_data {
};
struct context {
- GMainLoop *main_loop;
struct bt_uhid *uhid;
guint source;
guint process;
@@ -74,14 +75,14 @@ struct context {
static struct test_data data; \
data.test_name = g_strdup(name); \
data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
- g_test_add_data_func(name, &data, function); \
+ tester_add(name, &data, NULL, function, NULL); \
} while (0)
static void test_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
- g_print("%s%s\n", prefix, str);
+ tester_debug("%s%s\n", prefix, str);
}
static void test_free(gconstpointer user_data)
@@ -92,14 +93,29 @@ static void test_free(gconstpointer user_data)
g_free(data->pdu_list);
}
+static void destroy_context(struct context *context)
+{
+ if (context->source > 0)
+ g_source_remove(context->source);
+
+ bt_uhid_unref(context->uhid);
+
+ test_free(context->data);
+ g_free(context);
+}
+
static gboolean context_quit(gpointer user_data)
{
struct context *context = user_data;
+ if (context == NULL)
+ return FALSE;
+
if (context->process > 0)
g_source_remove(context->process);
- g_main_loop_quit(context->main_loop);
+ destroy_context(context);
+ tester_test_passed();
return FALSE;
}
@@ -114,8 +130,8 @@ static gboolean send_pdu(gpointer user_data)
len = write(context->fd, pdu->data, pdu->size);
- if (g_test_verbose())
- util_hexdump('<', pdu->data, len, test_debug, "uHID: ");
+
+ util_hexdump('<', pdu->data, len, test_debug, "uHID: ");
g_assert_cmpint(len, ==, pdu->size);
@@ -156,8 +172,7 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
g_assert(len > 0);
- if (g_test_verbose())
- util_hexdump('>', buf, len, test_debug, "uHID: ");
+ util_hexdump('>', buf, len, test_debug, "uHID: ");
g_assert_cmpint(len, ==, pdu->size);
@@ -174,9 +189,6 @@ static struct context *create_context(gconstpointer data)
GIOChannel *channel;
int err, sv[2];
- context->main_loop = g_main_loop_new(NULL, FALSE);
- g_assert(context->main_loop);
-
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
g_assert(err == 0);
@@ -202,26 +214,6 @@ static struct context *create_context(gconstpointer data)
return context;
}
-static void destroy_context(struct context *context)
-{
- if (context->source > 0)
- g_source_remove(context->source);
-
- bt_uhid_unref(context->uhid);
-
- g_main_loop_unref(context->main_loop);
-
- test_free(context->data);
- g_free(context);
-}
-
-static void execute_context(struct context *context)
-{
- g_main_loop_run(context->main_loop);
-
- destroy_context(context);
-}
-
static const struct uhid_event ev_create = {
.type = UHID_CREATE,
};
@@ -263,7 +255,7 @@ static void test_client(gconstpointer data)
if (g_str_equal(context->data->test_name, "/uhid/command/input"))
bt_uhid_send(context->uhid, &ev_input);
- execute_context(context);
+ context_quit(context);
}
static void handle_output(struct uhid_event *ev, void *user_data)
@@ -288,13 +280,11 @@ static void test_server(gconstpointer data)
bt_uhid_register(context->uhid, UHID_FEATURE, handle_feature, context);
g_idle_add(send_pdu, context);
-
- execute_context(context);
}
int main(int argc, char *argv[])
{
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
define_test("/uhid/command/create", test_client, event(&ev_create));
define_test("/uhid/command/destroy", test_client, event(&ev_destroy));
@@ -305,5 +295,5 @@ int main(int argc, char *argv[])
define_test("/uhid/event/output", test_server, event(&ev_output));
define_test("/uhid/event/feature", test_server, event(&ev_feature));
- return g_test_run();
+ return tester_run();
}
diff --git a/unit/test-uuid.c b/unit/test-uuid.c
index 60c47919..7c6789e3 100644
--- a/unit/test-uuid.c
+++ b/unit/test-uuid.c
@@ -29,6 +29,7 @@
#include "lib/bluetooth.h"
#include "lib/uuid.h"
+#include "src/shared/tester.h"
struct uuid_test_data {
const char *str;
@@ -128,8 +129,11 @@ static void test_uuid(gconstpointer data)
break;
case BT_UUID_UNSPEC:
default:
+ tester_test_passed();
return;
}
+
+ tester_test_passed();
}
static void test_str(gconstpointer data)
@@ -147,7 +151,7 @@ static void test_str(gconstpointer data)
g_assert(bt_string_to_uuid(&uuid, test_data->str) == 0);
bt_uuid_to_string(&uuid, buf, sizeof(buf));
- g_assert(strcasecmp(buf, str) == 0);
+ g_assert(bt_uuid_strcmp(buf, str) == 0);
switch (test_data->type) {
case BT_UUID16:
@@ -157,11 +161,13 @@ static void test_str(gconstpointer data)
bt_uuid32_create(&uuid, test_data->val32);
break;
default:
+ tester_test_passed();
return;
}
bt_uuid_to_string(&uuid, buf, sizeof(buf));
- g_assert(strcasecmp(buf, str) == 0);
+ g_assert(bt_uuid_strcmp(buf, str) == 0);
+ tester_test_passed();
}
static void test_cmp(gconstpointer data)
@@ -173,6 +179,7 @@ static void test_cmp(gconstpointer data)
g_assert(bt_string_to_uuid(&uuid2, test_data->str128) == 0);
g_assert(bt_uuid_cmp(&uuid1, &uuid2) == 0);
+ tester_test_passed();
}
static const struct uuid_test_data compress[] = {
@@ -220,43 +227,44 @@ static void test_malformed(gconstpointer data)
bt_uuid_t uuid;
g_assert(bt_string_to_uuid(&uuid, str) != 0);
+ tester_test_passed();
}
int main(int argc, char *argv[])
{
size_t i;
- g_test_init(&argc, &argv, NULL);
+ tester_init(&argc, &argv);
- g_test_add_data_func("/uuid/base", &uuid_base, test_uuid);
- g_test_add_data_func("/uuid/base/str", &uuid_base, test_str);
- g_test_add_data_func("/uuid/base/cmp", &uuid_base, test_cmp);
+ tester_add("/uuid/base", &uuid_base, NULL, test_uuid, NULL);
+ tester_add("/uuid/base/str", &uuid_base, NULL, test_str, NULL);
+ tester_add("/uuid/base/cmp", &uuid_base, NULL, test_cmp, NULL);
- g_test_add_data_func("/uuid/sixteen1", &uuid_sixteen1, test_uuid);
- g_test_add_data_func("/uuid/sixteen1/str", &uuid_sixteen1, test_str);
- g_test_add_data_func("/uuid/sixteen1/cmp", &uuid_sixteen1, test_cmp);
+ tester_add("/uuid/sixteen1", &uuid_sixteen1, NULL, test_uuid, NULL);
+ tester_add("/uuid/sixteen1/str", &uuid_sixteen1, NULL, test_str, NULL);
+ tester_add("/uuid/sixteen1/cmp", &uuid_sixteen1, NULL, test_cmp, NULL);
- g_test_add_data_func("/uuid/sixteen2", &uuid_sixteen2, test_uuid);
- g_test_add_data_func("/uuid/sixteen2/str", &uuid_sixteen2, test_str);
- g_test_add_data_func("/uuid/sixteen2/cmp", &uuid_sixteen2, test_cmp);
+ tester_add("/uuid/sixteen2", &uuid_sixteen2, NULL, test_uuid, NULL);
+ tester_add("/uuid/sixteen2/str", &uuid_sixteen2, NULL, test_str, NULL);
+ tester_add("/uuid/sixteen2/cmp", &uuid_sixteen2, NULL, test_cmp, NULL);
- g_test_add_data_func("/uuid/thirtytwo1", &uuid_32_1, test_uuid);
- g_test_add_data_func("/uuid/thirtytwo1/str", &uuid_32_1, test_str);
- g_test_add_data_func("/uuid/thirtytwo1/cmp", &uuid_32_1, test_cmp);
+ tester_add("/uuid/thirtytwo1", &uuid_32_1, NULL, test_uuid, NULL);
+ tester_add("/uuid/thirtytwo1/str", &uuid_32_1, NULL, test_str, NULL);
+ tester_add("/uuid/thirtytwo1/cmp", &uuid_32_1, NULL, test_cmp, NULL);
- g_test_add_data_func("/uuid/thirtytwo2", &uuid_32_2, test_uuid);
- g_test_add_data_func("/uuid/thritytwo2/str", &uuid_32_2, test_str);
- g_test_add_data_func("/uuid/thirtytwo2/cmp", &uuid_32_2, test_cmp);
+ tester_add("/uuid/thirtytwo2", &uuid_32_2, NULL, test_uuid, NULL);
+ tester_add("/uuid/thritytwo2/str", &uuid_32_2, NULL, test_str, NULL);
+ tester_add("/uuid/thirtytwo2/cmp", &uuid_32_2, NULL, test_cmp, NULL);
- g_test_add_data_func("/uuid/onetwentyeight", &uuid_128, test_uuid);
- g_test_add_data_func("/uuid/onetwentyeight/str", &uuid_128, test_str);
- g_test_add_data_func("/uuid/onetwentyeight/cmp", &uuid_128, test_cmp);
+ tester_add("/uuid/onetwentyeight", &uuid_128, NULL, test_uuid, NULL);
+ tester_add("/uuid/onetwentyeight/str", &uuid_128, NULL, test_str, NULL);
+ tester_add("/uuid/onetwentyeight/cmp", &uuid_128, NULL, test_cmp, NULL);
for (i = 0; malformed[i]; i++) {
char *testpath;
testpath = g_strdup_printf("/uuid/malformed/%s", malformed[i]);
- g_test_add_data_func(testpath, malformed[i], test_malformed);
+ tester_add(testpath, malformed[i], NULL, test_malformed, NULL);
g_free(testpath);
}
@@ -265,9 +273,9 @@ int main(int argc, char *argv[])
testpath = g_strdup_printf("/uuid/compress/%s",
compress[i].str);
- g_test_add_data_func(testpath, compress + i, test_uuid);
+ tester_add(testpath, compress + i, NULL, test_uuid, NULL);
g_free(testpath);
}
- return g_test_run();
+ return tester_run();
}