From 6330636b288f7aa8d179fb0967c7ccbe42cdd7b8 Mon Sep 17 00:00:00 2001 From: Paul Walko Date: Sat, 17 Dec 2016 04:18:30 -0500 Subject: [PATCH] ubertooth script --- ethernet_dhcp | 11 + ethernet_usb_dhcp | 11 + install | 1 + install.sh | 1 + libbtbb-2015-10-R1.tar.gz | Bin 0 -> 221859 bytes libbtbb-2015-10-R1/.gitignore | 17 + libbtbb-2015-10-R1/.travis.yml | 21 + libbtbb-2015-10-R1/CMakeLists.txt | 50 + libbtbb-2015-10-R1/README.cmake | 12 + libbtbb-2015-10-R1/README.md | 43 + libbtbb-2015-10-R1/cmake/cleanup.sh | 39 + .../cmake/cmake_uninstall.cmake.in | 32 + .../cmake/modules/CMakeParseArguments.cmake | 138 + .../cmake/modules/FindBTBB.cmake | 55 + .../cmake/modules/FindPCAP.cmake | 146 + .../FindPackageHandleStandardArgs.cmake | 299 ++ .../cmake/modules/FindPythonInterp.cmake | 141 + .../modules/GetGitRevisionDescription.cmake | 130 + .../GetGitRevisionDescription.cmake.in | 39 + libbtbb-2015-10-R1/lib/CMakeLists.txt | 39 + libbtbb-2015-10-R1/lib/libbtbb.pc.in | 11 + libbtbb-2015-10-R1/lib/src/CMakeLists.txt | 105 + .../lib/src/bluetooth_le_packet.c | 607 ++++ .../lib/src/bluetooth_le_packet.h | 74 + libbtbb-2015-10-R1/lib/src/bluetooth_packet.c | 1421 ++++++++ libbtbb-2015-10-R1/lib/src/bluetooth_packet.h | 147 + .../lib/src/bluetooth_piconet.c | 953 ++++++ .../lib/src/bluetooth_piconet.h | 131 + libbtbb-2015-10-R1/lib/src/btbb.h | 288 ++ libbtbb-2015-10-R1/lib/src/pcap-common.h | 129 + libbtbb-2015-10-R1/lib/src/pcap.c | 422 +++ libbtbb-2015-10-R1/lib/src/pcapng-bt.c | 522 +++ libbtbb-2015-10-R1/lib/src/pcapng-bt.h | 120 + libbtbb-2015-10-R1/lib/src/pcapng.c | 323 ++ libbtbb-2015-10-R1/lib/src/pcapng.h | 198 ++ libbtbb-2015-10-R1/lib/src/sw_check_tables.h | 4 + libbtbb-2015-10-R1/lib/src/uthash.h | 960 ++++++ libbtbb-2015-10-R1/packaging/Portfile | 34 + libbtbb-2015-10-R1/packaging/libbtbb.rb | 26 + libbtbb-2015-10-R1/packaging/libbtbb.spec | 64 + libbtbb-2015-10-R1/python/CMakeLists.txt | 40 + .../python/pcaptools/CMakeLists.txt | 38 + libbtbb-2015-10-R1/python/pcaptools/Makefile | 39 + libbtbb-2015-10-R1/python/pcaptools/README | 20 + libbtbb-2015-10-R1/python/pcaptools/btaptap | 520 +++ .../python/pcaptools/pcapdump/__init__.py | 0 .../python/pcaptools/pcapdump/pcapdump.py | 193 ++ libbtbb-2015-10-R1/python/pcaptools/setup.py | 31 + .../python/pcaptools/setup.py.in | 32 + .../pcaptools/tests/ellysis-keyboard.csv | 866 +++++ libbtbb-2015-10-R1/python/utils/encode_sw.py | 67 + .../python/utils/gen_barker_correct.py | 23 + .../python/utils/gen_check_tables.py | 59 + .../python/utils/le_whitening.py | 21 + libbtbb-2015-10-R1/tests/Makefile | 36 + libbtbb-2015-10-R1/tests/test_fec23.c | 122 + libbtbb-2015-10-R1/tests/test_header.c | 118 + libbtbb-2015-10-R1/tests/test_syndromes.c | 100 + libbtbb-2015-10-R1/web/index.html | 40 + .../wireshark/plugins/btatt/AUTHORS | 5 + .../wireshark/plugins/btatt/CMakeLists.txt | 88 + .../wireshark/plugins/btatt/COPYING | 340 ++ .../wireshark/plugins/btatt/Makefile.am | 125 + .../wireshark/plugins/btatt/Makefile.common | 39 + .../wireshark/plugins/btatt/Makefile.nmake | 100 + .../wireshark/plugins/btatt/README | 11 + .../wireshark/plugins/btatt/cmake/COPYING | 22 + .../plugins/btatt/cmake/COPYING-CMAKE-SCRIPTS | 27 + .../plugins/btatt/cmake/FindGLIB2.cmake | 238 ++ .../plugins/btatt/cmake/FindWireshark.cmake | 28 + .../btatt/cmake/UseMakeDissectorReg.cmake | 33 + .../wireshark/plugins/btatt/moduleinfo.h | 17 + .../wireshark/plugins/btatt/moduleinfo.nmake | 28 + .../wireshark/plugins/btatt/packet-btatt.c | 698 ++++ .../wireshark/plugins/btatt/plugin.rc.in | 34 + .../plugins/btatt/tools/make-dissector-reg | 186 ++ .../plugins/btatt/tools/make-dissector-reg.py | 311 ++ .../wireshark/plugins/btbb/AUTHORS | 2 + .../wireshark/plugins/btbb/CMakeLists.txt | 89 + .../wireshark/plugins/btbb/COPYING | 340 ++ .../wireshark/plugins/btbb/README | 17 + .../plugins/btbb/btbb-sample-mouse.pcap | Bin 0 -> 2541 bytes .../wireshark/plugins/btbb/cmake/COPYING | 22 + .../plugins/btbb/cmake/COPYING-CMAKE-SCRIPTS | 27 + .../plugins/btbb/cmake/FindGLIB2.cmake | 238 ++ .../plugins/btbb/cmake/FindWireshark.cmake | 28 + .../btbb/cmake/UseMakeDissectorReg.cmake | 33 + .../wireshark/plugins/btbb/moduleinfo.h | 17 + .../wireshark/plugins/btbb/packet-btbb.c | 593 ++++ .../wireshark/plugins/btbb/packet-btbrlmp.c | 2887 +++++++++++++++++ .../wireshark/plugins/btbb/plugin.rc.in | 34 + .../plugins/btbb/tools/make-dissector-reg | 186 ++ .../plugins/btbb/tools/make-dissector-reg.py | 311 ++ .../wireshark/plugins/btbredr/AUTHORS | 3 + .../wireshark/plugins/btbredr/CMakeLists.txt | 86 + .../wireshark/plugins/btbredr/COPYING | 340 ++ .../wireshark/plugins/btbredr/README | 16 + .../plugins/btbredr/btbredr_test.pcap | Bin 0 -> 4793 bytes .../wireshark/plugins/btbredr/cmake/COPYING | 22 + .../btbredr/cmake/COPYING-CMAKE-SCRIPTS | 27 + .../plugins/btbredr/cmake/FindGLIB2.cmake | 238 ++ .../plugins/btbredr/cmake/FindWireshark.cmake | 28 + .../btbredr/cmake/UseMakeDissectorReg.cmake | 33 + .../wireshark/plugins/btbredr/moduleinfo.h | 17 + .../plugins/btbredr/packet-btbredr.c | 673 ++++ .../wireshark/plugins/btbredr/packet-btlmp.c | 2887 +++++++++++++++++ .../wireshark/plugins/btbredr/plugin.rc.in | 34 + .../plugins/btbredr/tools/make-dissector-reg | 186 ++ .../btbredr/tools/make-dissector-reg.py | 311 ++ .../wireshark/plugins/btle/AUTHORS | 3 + .../wireshark/plugins/btle/CMakeLists.txt | 88 + .../wireshark/plugins/btle/COPYING | 340 ++ .../wireshark/plugins/btle/Makefile.am | 125 + .../wireshark/plugins/btle/Makefile.common | 39 + .../wireshark/plugins/btle/Makefile.nmake | 100 + .../wireshark/plugins/btle/README | 61 + .../wireshark/plugins/btle/cmake/COPYING | 22 + .../plugins/btle/cmake/COPYING-CMAKE-SCRIPTS | 27 + .../plugins/btle/cmake/FindGLIB2.cmake | 238 ++ .../plugins/btle/cmake/FindWireshark.cmake | 28 + .../btle/cmake/UseMakeDissectorReg.cmake | 33 + .../wireshark/plugins/btle/moduleinfo.h | 17 + .../wireshark/plugins/btle/moduleinfo.nmake | 28 + .../wireshark/plugins/btle/packet-btle.c | 665 ++++ .../wireshark/plugins/btle/plugin.rc.in | 34 + .../plugins/btle/tools/make-dissector-reg | 186 ++ .../plugins/btle/tools/make-dissector-reg.py | 311 ++ .../plugins/btle/wireshark-1.8-btle-ppi.patch | 246 ++ .../wireshark/plugins/btsm/AUTHORS | 3 + .../wireshark/plugins/btsm/CMakeLists.txt | 88 + .../wireshark/plugins/btsm/COPYING | 340 ++ .../wireshark/plugins/btsm/Makefile.am | 125 + .../wireshark/plugins/btsm/Makefile.common | 39 + .../wireshark/plugins/btsm/Makefile.nmake | 100 + .../wireshark/plugins/btsm/README | 14 + .../wireshark/plugins/btsm/cmake/COPYING | 22 + .../plugins/btsm/cmake/COPYING-CMAKE-SCRIPTS | 27 + .../plugins/btsm/cmake/FindGLIB2.cmake | 238 ++ .../plugins/btsm/cmake/FindWireshark.cmake | 28 + .../btsm/cmake/UseMakeDissectorReg.cmake | 33 + .../wireshark/plugins/btsm/moduleinfo.h | 17 + .../wireshark/plugins/btsm/moduleinfo.nmake | 28 + .../wireshark/plugins/btsm/packet-btsm.c | 381 +++ .../wireshark/plugins/btsm/plugin.rc.in | 34 + .../plugins/btsm/tools/make-dissector-reg | 186 ++ .../plugins/btsm/tools/make-dissector-reg.py | 311 ++ ubertooth_install.sh | 124 + ubertooth_ubuntu160401.sh | 49 - 148 files changed, 26913 insertions(+), 49 deletions(-) create mode 100644 ethernet_dhcp create mode 100644 ethernet_usb_dhcp create mode 100755 install create mode 100755 install.sh create mode 100644 libbtbb-2015-10-R1.tar.gz create mode 100644 libbtbb-2015-10-R1/.gitignore create mode 100644 libbtbb-2015-10-R1/.travis.yml create mode 100644 libbtbb-2015-10-R1/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/README.cmake create mode 100644 libbtbb-2015-10-R1/README.md create mode 100755 libbtbb-2015-10-R1/cmake/cleanup.sh create mode 100644 libbtbb-2015-10-R1/cmake/cmake_uninstall.cmake.in create mode 100644 libbtbb-2015-10-R1/cmake/modules/CMakeParseArguments.cmake create mode 100644 libbtbb-2015-10-R1/cmake/modules/FindBTBB.cmake create mode 100644 libbtbb-2015-10-R1/cmake/modules/FindPCAP.cmake create mode 100644 libbtbb-2015-10-R1/cmake/modules/FindPackageHandleStandardArgs.cmake create mode 100644 libbtbb-2015-10-R1/cmake/modules/FindPythonInterp.cmake create mode 100644 libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake create mode 100644 libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake.in create mode 100644 libbtbb-2015-10-R1/lib/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/lib/libbtbb.pc.in create mode 100644 libbtbb-2015-10-R1/lib/src/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.c create mode 100644 libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.h create mode 100644 libbtbb-2015-10-R1/lib/src/bluetooth_packet.c create mode 100644 libbtbb-2015-10-R1/lib/src/bluetooth_packet.h create mode 100644 libbtbb-2015-10-R1/lib/src/bluetooth_piconet.c create mode 100644 libbtbb-2015-10-R1/lib/src/bluetooth_piconet.h create mode 100644 libbtbb-2015-10-R1/lib/src/btbb.h create mode 100644 libbtbb-2015-10-R1/lib/src/pcap-common.h create mode 100644 libbtbb-2015-10-R1/lib/src/pcap.c create mode 100644 libbtbb-2015-10-R1/lib/src/pcapng-bt.c create mode 100644 libbtbb-2015-10-R1/lib/src/pcapng-bt.h create mode 100644 libbtbb-2015-10-R1/lib/src/pcapng.c create mode 100644 libbtbb-2015-10-R1/lib/src/pcapng.h create mode 100644 libbtbb-2015-10-R1/lib/src/sw_check_tables.h create mode 100644 libbtbb-2015-10-R1/lib/src/uthash.h create mode 100644 libbtbb-2015-10-R1/packaging/Portfile create mode 100644 libbtbb-2015-10-R1/packaging/libbtbb.rb create mode 100644 libbtbb-2015-10-R1/packaging/libbtbb.spec create mode 100644 libbtbb-2015-10-R1/python/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/python/pcaptools/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/python/pcaptools/Makefile create mode 100644 libbtbb-2015-10-R1/python/pcaptools/README create mode 100755 libbtbb-2015-10-R1/python/pcaptools/btaptap create mode 100644 libbtbb-2015-10-R1/python/pcaptools/pcapdump/__init__.py create mode 100644 libbtbb-2015-10-R1/python/pcaptools/pcapdump/pcapdump.py create mode 100755 libbtbb-2015-10-R1/python/pcaptools/setup.py create mode 100755 libbtbb-2015-10-R1/python/pcaptools/setup.py.in create mode 100644 libbtbb-2015-10-R1/python/pcaptools/tests/ellysis-keyboard.csv create mode 100755 libbtbb-2015-10-R1/python/utils/encode_sw.py create mode 100755 libbtbb-2015-10-R1/python/utils/gen_barker_correct.py create mode 100755 libbtbb-2015-10-R1/python/utils/gen_check_tables.py create mode 100755 libbtbb-2015-10-R1/python/utils/le_whitening.py create mode 100644 libbtbb-2015-10-R1/tests/Makefile create mode 100644 libbtbb-2015-10-R1/tests/test_fec23.c create mode 100644 libbtbb-2015-10-R1/tests/test_header.c create mode 100644 libbtbb-2015-10-R1/tests/test_syndromes.c create mode 100644 libbtbb-2015-10-R1/web/index.html create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/AUTHORS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.am create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.common create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.nmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/README create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING-CMAKE-SCRIPTS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindGLIB2.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindWireshark.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/UseMakeDissectorReg.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.h create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.nmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/packet-btatt.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btatt/plugin.rc.in create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg.py create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/AUTHORS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/README create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/btbb-sample-mouse.pcap create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/COPYING-CMAKE-SCRIPTS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/FindGLIB2.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/FindWireshark.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/UseMakeDissectorReg.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/moduleinfo.h create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbb.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbrlmp.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbb/plugin.rc.in create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg.py create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/AUTHORS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/README create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/btbredr_test.pcap create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING-CMAKE-SCRIPTS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindGLIB2.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindWireshark.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/UseMakeDissectorReg.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/moduleinfo.h create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btbredr.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btlmp.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btbredr/plugin.rc.in create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg.py create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/AUTHORS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.am create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.common create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.nmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/README create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING-CMAKE-SCRIPTS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindGLIB2.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindWireshark.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/UseMakeDissectorReg.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.h create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.nmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/packet-btle.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/plugin.rc.in create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg.py create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btle/wireshark-1.8-btle-ppi.patch create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/AUTHORS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/CMakeLists.txt create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.am create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.common create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.nmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/README create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING-CMAKE-SCRIPTS create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindGLIB2.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindWireshark.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/UseMakeDissectorReg.cmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.h create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.nmake create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/packet-btsm.c create mode 100644 libbtbb-2015-10-R1/wireshark/plugins/btsm/plugin.rc.in create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg create mode 100755 libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg.py create mode 100755 ubertooth_install.sh delete mode 100755 ubertooth_ubuntu160401.sh diff --git a/ethernet_dhcp b/ethernet_dhcp new file mode 100644 index 0000000..88b45d5 --- /dev/null +++ b/ethernet_dhcp @@ -0,0 +1,11 @@ +Description='A basic dhcp ethernet connection' +Interface=eno1 +Connection=ethernet +IP=dhcp +#DHCPClient=dhcpcd +#DHCPReleaseOnStop=no +## for DHCPv6 +IP6=dhcp +DHCP6Client=dhclient +## for IPv6 autoconfiguration +IP6=stateless diff --git a/ethernet_usb_dhcp b/ethernet_usb_dhcp new file mode 100644 index 0000000..4a846e6 --- /dev/null +++ b/ethernet_usb_dhcp @@ -0,0 +1,11 @@ +Description='A basic dhcp ethernet connection' +Interface=enp0s20u1u3 +Connection=ethernet +IP=dhcp +#DHCPClient=dhcpcd +#DHCPReleaseOnStop=no +## for DHCPv6 +IP6=dhcp +DHCP6Client=dhclient +## for IPv6 autoconfiguration +IP6=stateless diff --git a/install b/install new file mode 100755 index 0000000..87ab71d --- /dev/null +++ b/install @@ -0,0 +1 @@ +sudo pacman -S syncthing alsa alsa-utils pulseaudio pavucontrol i3 xf86-86-video-amdgpu mesa-libgl lib32-mesa-libgl mesa-vdpau lib32-mesa-vdpau firefox openssh flashplugin diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..87ab71d --- /dev/null +++ b/install.sh @@ -0,0 +1 @@ +sudo pacman -S syncthing alsa alsa-utils pulseaudio pavucontrol i3 xf86-86-video-amdgpu mesa-libgl lib32-mesa-libgl mesa-vdpau lib32-mesa-vdpau firefox openssh flashplugin diff --git a/libbtbb-2015-10-R1.tar.gz b/libbtbb-2015-10-R1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4de0a6925416d2c5e2c5c4be8f6c9c552933c90b GIT binary patch literal 221859 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 literal 0 HcmV?d00001 diff --git a/libbtbb-2015-10-R1/.gitignore b/libbtbb-2015-10-R1/.gitignore new file mode 100644 index 0000000..d033927 --- /dev/null +++ b/libbtbb-2015-10-R1/.gitignore @@ -0,0 +1,17 @@ +*.o +*.so.* +*.so +*.pyc + +# Output directory +build/ + +# wireshark plugins +CMakeCache.txt +CMakeFiles +cmake_install.cmake +install_manifest.txt +plugin.c +wireshark/plugins/btatt/Makefile +wireshark/plugins/btle/Makefile +wireshark/plugins/btsm/Makefile diff --git a/libbtbb-2015-10-R1/.travis.yml b/libbtbb-2015-10-R1/.travis.yml new file mode 100644 index 0000000..02f371a --- /dev/null +++ b/libbtbb-2015-10-R1/.travis.yml @@ -0,0 +1,21 @@ +language: c + +cache: apt + +sudo: false + +addons: + apt: + packages: + - libpcap-dev + +compiler: + - clang + - gcc + +before_script: + - mkdir build + - cd build + - CFLAGS="-g -Wall -Wextra -Werror -Wno-zero-length-array" cmake .. + +script: make diff --git a/libbtbb-2015-10-R1/CMakeLists.txt b/libbtbb-2015-10-R1/CMakeLists.txt new file mode 100644 index 0000000..93e6c20 --- /dev/null +++ b/libbtbb-2015-10-R1/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# Copyright 2013 Dominic Spill +# +# This file is part of Libbtbb. +# +# 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, 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# +#top level cmake project for libbtbb lib + tools + +cmake_minimum_required(VERSION 2.8) +set(MAJOR_VERSION 0) +set(MINOR_VERSION 3) +project(libbtbb_all) +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) + +set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") + +set( VERSION ${MAJOR_VERSION}.${MINOR_VERSION} ) +add_definitions( -DVERSION="${VERSION}" ) + +# Comment the following out for releases. +set(CMAKE_C_FLAGS "$ENV{CFLAGS}") + +add_subdirectory(lib) +if(NOT DISABLE_PYTHON) + add_subdirectory(python) +endif() + +# Create uninstall target +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +@ONLY) + +add_custom_target(uninstall + ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +) diff --git a/libbtbb-2015-10-R1/README.cmake b/libbtbb-2015-10-R1/README.cmake new file mode 100644 index 0000000..b9cc4ba --- /dev/null +++ b/libbtbb-2015-10-R1/README.cmake @@ -0,0 +1,12 @@ +CMake Settings +============== +The following are flags that may be of use when configuing this project. + + * DISABLE_PYTHON + * A boolean flag for building and installing btaptap python tool. + + * USE_PCAP + * USE_PCAP=ON - Build with pcap support, the build will fail if + libpcap is not found. + * USE_PCAP=OFF - Disable pcap support will be disabled. + * If left undefined pcap support will be enabled if libpcap is present. diff --git a/libbtbb-2015-10-R1/README.md b/libbtbb-2015-10-R1/README.md new file mode 100644 index 0000000..dd36486 --- /dev/null +++ b/libbtbb-2015-10-R1/README.md @@ -0,0 +1,43 @@ +libbtbb +======= + +This is the Bluetooth baseband decoding library, forked from the GR-Bluetooth +project. It can be used to extract Bluetooth packet and piconet information +from Ubertooth devices as well as GR-Bluetooth/USRP. + +This code is incomplete, it is still under active development. Patches and +bug reports should be submitted to the bug tracker on GitHub: +https://github.com/greatscottgadgets/libbtbb/issues + +This software has been developed and tested on Linux, it should work on other +platforms but this has yet to be tested. + + +Build Instructions +================== + +Libbtbb can be built and installed as follows: +``` +$ mkdir build +$ cd build +$ cmake .. +$ make +$ sudo make install +``` + +This will install the library to /usr/local/lib and the headers to +/usr/local/include, to install to different locations use: +``` +$ cmake -DINSTALL_DIR=/path/to/install -DINCLUDE_DIR=/path/to/include .. +``` + +If you have previous versions of libbtbb, libubertooth or the Ubertooth tools +installed, you can use the cleanup script to remove them: +``` +$ sudo cmake/cleanup.sh -d +``` + +To list the installed files without removing them, use: +``` +$ cmake/cleanup.sh +``` diff --git a/libbtbb-2015-10-R1/cmake/cleanup.sh b/libbtbb-2015-10-R1/cmake/cleanup.sh new file mode 100755 index 0000000..a08838d --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/cleanup.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# A quick and dirty script to remove old installs of +# libbtbb, libubertooth and associated Ubertooth tools +# Copyright 2014 Dominic Spill +# License: GPL v2 + +FIND=`which find` + +INSTALL_DIRS="/usr /usr/local" + +LIBS="btbb ubertooth" + +HEADERS="bluetooth_packet.h \ + bluetooth_piconet.h \ + bluetooth_le_packet.h \ + ubertooth_interface.h \ + ubertooth_control.h \ + ubertooth.h \ + " + +if [ "$1" == "-d" ] +then + EXEC="-print -exec rm -f {} ;" + echo "Deleting previous installs:" +else + EXEC=-print + echo 'Installed files, use "sudo cleanup.sh -d" to delete these files' +fi + +for dir in $INSTALL_DIRS; do + for lib in $LIBS; do + $FIND ${dir}/lib -maxdepth 1 -name "lib$lib.so*" $EXEC + done + for header in $HEADERS; do + $FIND ${dir}/include -maxdepth 1 -name "$header" $EXEC + done + $FIND ${dir}/bin -maxdepth 1 -name "ubertooth-*" $EXEC +done diff --git a/libbtbb-2015-10-R1/cmake/cmake_uninstall.cmake.in b/libbtbb-2015-10-R1/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..9ae1ae4 --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,32 @@ +# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F + +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/libbtbb-2015-10-R1/cmake/modules/CMakeParseArguments.cmake b/libbtbb-2015-10-R1/cmake/modules/CMakeParseArguments.cmake new file mode 100644 index 0000000..406780e --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/CMakeParseArguments.cmake @@ -0,0 +1,138 @@ +# CMAKE_PARSE_ARGUMENTS( args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for +# parsing the arguments given to that macro or function. +# It processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any value +# following, like e.g. the OPTIONAL keyword of the install() command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this macro +# which can be followed by more than one value, like e.g. the TARGETS or +# FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. +# These variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether +# your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments as the +# real install() command: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) +# ... +# +# Assume my_install() has been called like this: +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# After the cmake_parse_arguments() call the macro will have set the following +# variables: +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# You can the continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a one_value_keyword +# another recognized keyword follows, this is interpreted as the beginning of +# the new option. +# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would +# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach() + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach() + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else() + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif() + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach() + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach() + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction() diff --git a/libbtbb-2015-10-R1/cmake/modules/FindBTBB.cmake b/libbtbb-2015-10-R1/cmake/modules/FindBTBB.cmake new file mode 100644 index 0000000..45ed432 --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/FindBTBB.cmake @@ -0,0 +1,55 @@ +# Try to find the libbtbb library +# +# Once done this defines: +# LIBBTBB_FOUND - system has libbtbb +# LIBBTBB_INCLUDE_DIR - the libbtbb include directory +# LIBBTBB_LIBRARIES - Link these to use libbtbb +# +# Copyright (c) 2013 Dominic Spill + + +if (LIBBTBB_INCLUDE_DIR AND LIBBTBB_LIBRARIES) + + # in cache already + set(LIBBTBB_FOUND TRUE) + +else (LIBBTBB_INCLUDE_DIR AND LIBBTBB_LIBRARIES) + IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PC_LIBBTBB QUIET libbtbb) + ENDIF(NOT WIN32) + + FIND_PATH(LIBBTBB_INCLUDE_DIR + NAMES btbb.h + HINTS $ENV{LIBBTBB_DIR}/include ${PC_LIBBTBB_INCLUDEDIR} + PATHS /usr/include /usr/local/include + /opt/local/include + ${CMAKE_SOURCE_DIR}/../libbtbb/src + ${LIBBTBB_INCLUDE_DIR} + ) + + set(libbtbb_library_names btbb) + + FIND_LIBRARY(LIBBTBB_LIBRARIES + NAMES ${libbtbb_library_names} + HINTS $ENV{LIBBTBB_DIR}/lib ${PC_LIBBTBB_LIBDIR} + PATHS /usr/local/lib /usr/lib /opt/local/lib ${PC_LIBBTBB_LIBDIR} + ${PC_LIBBTBB_LIBRARY_DIRS} ${CMAKE_SOURCE_DIR}/../libbtbb/src + ) + + if(LIBBTBB_INCLUDE_DIR) + set(CMAKE_REQUIRED_INCLUDES ${LIBBTBB_INCLUDE_DIR}) + endif() + + if(LIBBTBB_LIBRARIES) + set(CMAKE_REQUIRED_LIBRARIES ${LIBBTBB_LIBRARIES}) + endif() + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBBTBB DEFAULT_MSG LIBBTBB_LIBRARIES LIBBTBB_INCLUDE_DIR) + + MARK_AS_ADVANCED(LIBBTBB_INCLUDE_DIR LIBBTBB_LIBRARIES) + +endif (LIBBTBB_INCLUDE_DIR AND LIBBTBB_LIBRARIES) \ No newline at end of file diff --git a/libbtbb-2015-10-R1/cmake/modules/FindPCAP.cmake b/libbtbb-2015-10-R1/cmake/modules/FindPCAP.cmake new file mode 100644 index 0000000..512ed78 --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/FindPCAP.cmake @@ -0,0 +1,146 @@ +# +# $Id: FindPCAP.cmake 38372 2011-08-05 18:52:53Z gerald $ +# +################################################################### +# +# Copyright (c) 2006 Frederic Heem, +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the Telsey nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +################################################################### +# - Find pcap +# Find the PCAP includes and library +# http://www.tcpdump.org/ +# +# The environment variable PCAPDIR allows to specficy where to find +# libpcap in non standard location. +# +# PCAP_INCLUDE_DIRS - where to find pcap.h, etc. +# PCAP_LIBRARIES - List of libraries when using pcap. +# PCAP_FOUND - True if pcap found. + + +IF(EXISTS $ENV{PCAPDIR}) + FIND_PATH(PCAP_INCLUDE_DIR + NAMES + pcap/pcap.h + pcap.h + PATHS + $ENV{PCAPDIR} + NO_DEFAULT_PATH + ) + + FIND_LIBRARY(PCAP_LIBRARY + NAMES + pcap + PATHS + $ENV{PCAPDIR} + NO_DEFAULT_PATH + ) + + +ELSE(EXISTS $ENV{PCAPDIR}) + FIND_PATH(PCAP_INCLUDE_DIR + NAMES + pcap/pcap.h + pcap.h + HINTS + /usr/local/opt/libpcap/include + ) + + FIND_LIBRARY(PCAP_LIBRARY + NAMES + pcap + HINTS + /usr/local/opt/libpcap/lib + ) + +ENDIF(EXISTS $ENV{PCAPDIR}) + +SET(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR}) +SET(PCAP_LIBRARIES ${PCAP_LIBRARY}) + +IF(PCAP_INCLUDE_DIRS) + MESSAGE(STATUS "Pcap include dirs set to ${PCAP_INCLUDE_DIRS}") +ELSE(PCAP_INCLUDE_DIRS) + MESSAGE(FATAL " Pcap include dirs cannot be found") +ENDIF(PCAP_INCLUDE_DIRS) + +IF(PCAP_LIBRARIES) + MESSAGE(STATUS "Pcap library set to ${PCAP_LIBRARIES}") +ELSE(PCAP_LIBRARIES) + MESSAGE(FATAL "Pcap library cannot be found") +ENDIF(PCAP_LIBRARIES) + +#Functions +INCLUDE(CheckFunctionExists) +INCLUDE(CheckVariableExists) +SET(CMAKE_REQUIRED_INCLUDES ${PCAP_INCLUDE_DIRS}) +SET(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARIES}) +CHECK_VARIABLE_EXISTS("pcap_version" HAVE_PCAP_VERSION) +CHECK_FUNCTION_EXISTS("pcap_open_dead" HAVE_PCAP_OPEN_DEAD) +CHECK_FUNCTION_EXISTS("pcap_freecode" HAVE_PCAP_FREECODE) +# +# Note: for pcap_breakloop() and pcap_findalldevs(), the autoconf script +# checks for more than just whether the function exists, it also checks +# for whether pcap.h declares it; Mac OS X software/security updates can +# update libpcap without updating the headers. +# +CHECK_FUNCTION_EXISTS("pcap_breakloop" HAVE_PCAP_BREAKLOOP) +CHECK_FUNCTION_EXISTS("pcap_create" HAVE_PCAP_CREATE) +CHECK_FUNCTION_EXISTS("pcap_datalink_name_to_val" HAVE_PCAP_DATALINK_NAME_TO_VAL) +CHECK_FUNCTION_EXISTS("pcap_datalink_val_to_description" HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION) +CHECK_FUNCTION_EXISTS("pcap_datalink_val_to_name" HAVE_PCAP_DATALINK_VAL_TO_NAME) +CHECK_FUNCTION_EXISTS("pcap_findalldevs" HAVE_PCAP_FINDALLDEVS) +CHECK_FUNCTION_EXISTS("pcap_free_datalinks" HAVE_PCAP_FREE_DATALINKS) +CHECK_FUNCTION_EXISTS("pcap_get_selectable_fd" HAVE_PCAP_GET_SELECTABLE_FD) +CHECK_FUNCTION_EXISTS("pcap_lib_version" HAVE_PCAP_LIB_VERSION) +CHECK_FUNCTION_EXISTS("pcap_list_datalinks" HAVE_PCAP_LIST_DATALINKS) +CHECK_FUNCTION_EXISTS("pcap_set_datalink" HAVE_PCAP_SET_DATALINK) +# Remote pcap checks +CHECK_FUNCTION_EXISTS("pcap_open" H_PCAP_OPEN) +CHECK_FUNCTION_EXISTS("pcap_findalldevs_ex" H_FINDALLDEVS_EX) +CHECK_FUNCTION_EXISTS("pcap_createsrcstr" H_CREATESRCSTR) +if(H_PCAP_OPEN AND H_FINDALLDEVS_EX AND H_CREATESRCSTR) + SET(HAVE_PCAP_REMOTE 1) + SET(HAVE_REMOTE 1) +endif() +# reset vars +SET(CMAKE_REQUIRED_INCLUDES "") +SET(CMAKE_REQUIRED_LIBRARIES "") + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCAP DEFAULT_MSG PCAP_INCLUDE_DIRS PCAP_LIBRARIES) + +MARK_AS_ADVANCED( + PCAP_LIBRARIES + PCAP_INCLUDE_DIRS +) diff --git a/libbtbb-2015-10-R1/cmake/modules/FindPackageHandleStandardArgs.cmake b/libbtbb-2015-10-R1/cmake/modules/FindPackageHandleStandardArgs.cmake new file mode 100644 index 0000000..25d8df3 --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,299 @@ +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) +# +# This function is intended to be used in FindXXX.cmake modules files. +# It handles the REQUIRED, QUIET and version-related arguments to find_package(). +# It also sets the _FOUND variable. +# The package is considered found if all variables ... listed contain +# valid results, e.g. valid filepaths. +# +# There are two modes of this function. The first argument in both modes is +# the name of the Find-module where it is called (in original casing). +# +# The first simple mode looks like this: +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( (DEFAULT_MSG|"Custom failure message") ... ) +# If the variables to are all valid, then _FOUND +# will be set to TRUE. +# If DEFAULT_MSG is given as second argument, then the function will generate +# itself useful success and error messages. You can also supply a custom error message +# for the failure case. This is not recommended. +# +# The second mode is more powerful and also supports version checking: +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME [REQUIRED_VARS ...] +# [VERSION_VAR ] +# [HANDLE_COMPONENTS] +# [CONFIG_MODE] +# [FAIL_MESSAGE "Custom failure message"] ) +# +# As above, if through are all valid, _FOUND +# will be set to TRUE. +# After REQUIRED_VARS the variables which are required for this package are listed. +# Following VERSION_VAR the name of the variable can be specified which holds +# the version of the package which has been found. If this is done, this version +# will be checked against the (potentially) specified required version used +# in the find_package() call. The EXACT keyword is also handled. The default +# messages include information about the required version and the version +# which has been actually found, both if the version is ok or not. +# If the package supports components, use the HANDLE_COMPONENTS option to enable +# handling them. In this case, find_package_handle_standard_args() will report +# which components have been found and which are missing, and the _FOUND +# variable will be set to FALSE if any of the required components (i.e. not the +# ones listed after OPTIONAL_COMPONENTS) are missing. +# Use the option CONFIG_MODE if your FindXXX.cmake module is a wrapper for +# a find_package(... NO_MODULE) call. In this case VERSION_VAR will be set +# to _VERSION and the macro will automatically check whether the +# Config module was found. +# Via FAIL_MESSAGE a custom failure message can be specified, if this is not +# used, the default message will be displayed. +# +# Example for mode 1: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# +# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and +# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE. +# If it is not found and REQUIRED was used, it fails with FATAL_ERROR, +# independent whether QUIET was used or not. +# If it is found, success will be reported, including the content of . +# On repeated Cmake runs, the same message won't be printed again. +# +# Example for mode 2: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON REQUIRED_VARS BISON_EXECUTABLE +# VERSION_VAR BISON_VERSION) +# In this case, BISON is considered to be found if the variable(s) listed +# after REQUIRED_VAR are all valid, i.e. BISON_EXECUTABLE in this case. +# Also the version of BISON will be checked by using the version contained +# in BISON_VERSION. +# Since no FAIL_MESSAGE is given, the default messages will be printed. +# +# Another example for mode 2: +# +# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(Automoc4 CONFIG_MODE) +# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4 NO_MODULE) +# and adds an additional search directory for automoc4. +# The following FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper +# success/error message. + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +include(FindPackageMessage) +include(CMakeParseArguments) + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${_msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${_msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + set(configsText "${configsText} ${filename} (version ${version})\n") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + set(options CONFIG_MODE HANDLE_COMPONENTS) + set(oneValueArgs FAIL_MESSAGE VERSION_VAR) + set(multiValueArgs REQUIRED_VARS) + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + endif() + +# now that we collected all arguments, process them + + if("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + set(${_NAME_UPPER}_FOUND TRUE) + # check if all passed variables are valid + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(${_NAME_UPPER}_FOUND FALSE) + set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") + else() + set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") + endif() + endforeach() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components: ") + endif() + set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components: ") + endif() + set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME_UPPER}_FOUND FALSE) + set(MISSING_VARS "${MISSING_VARS} ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + set(VERSION ${${FPHSA_VERSION_VAR}} ) + if (${_NAME}_FIND_VERSION) + + if(VERSION) + + if(${_NAME}_FIND_VERSION_EXACT) # exact version required + if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + + else() # minimum version specified: + if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") + endif () + endif() + + else() + + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + + endif() + else () + if(VERSION) + set(VERSION_MSG "(found version \"${VERSION}\")") + endif() + endif () + + if(VERSION_OK) + set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") + else() + set(${_NAME_UPPER}_FOUND FALSE) + endif() + + + # print the result: + if (${_NAME_UPPER}_FOUND) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_NAME_UPPER}_FOUND ${${_NAME_UPPER}_FOUND} PARENT_SCOPE) + +endfunction() diff --git a/libbtbb-2015-10-R1/cmake/modules/FindPythonInterp.cmake b/libbtbb-2015-10-R1/cmake/modules/FindPythonInterp.cmake new file mode 100644 index 0000000..7fb65b8 --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/FindPythonInterp.cmake @@ -0,0 +1,141 @@ +# - Find python interpreter +# This module finds if Python interpreter is installed and determines where the +# executables are. This code sets the following variables: +# +# PYTHONINTERP_FOUND - Was the Python executable found +# PYTHON_EXECUTABLE - path to the Python interpreter +# +# PYTHON_VERSION_STRING - Python version found e.g. 2.5.2 +# PYTHON_VERSION_MAJOR - Python major version found e.g. 2 +# PYTHON_VERSION_MINOR - Python minor version found e.g. 5 +# PYTHON_VERSION_PATCH - Python patch version found e.g. 2 +# +# The Python_ADDITIONAL_VERSIONS variable can be used to specify a list of +# version numbers that should be taken into account when searching for Python. +# You need to set this variable before calling find_package(PythonInterp). + +#============================================================================= +# Copyright 2005-2010 Kitware, Inc. +# Copyright 2011 Bjoern Ricks +# Copyright 2012 Rolf Eike Beer +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +unset(_Python_NAMES) + +set(_PYTHON1_VERSIONS 1.6 1.5) +set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) +set(_PYTHON3_VERSIONS 3.3 3.2 3.1 3.0) + +if(PythonInterp_FIND_VERSION) + if(PythonInterp_FIND_VERSION MATCHES "^[0-9]+\\.[0-9]+(\\.[0-9]+.*)?$") + string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" _PYTHON_FIND_MAJ_MIN "${PythonInterp_FIND_VERSION}") + string(REGEX REPLACE "^([0-9]+).*" "\\1" _PYTHON_FIND_MAJ "${_PYTHON_FIND_MAJ_MIN}") + list(APPEND _Python_NAMES python${_PYTHON_FIND_MAJ_MIN} python${_PYTHON_FIND_MAJ}) + unset(_PYTHON_FIND_OTHER_VERSIONS) + if(NOT PythonInterp_FIND_VERSION_EXACT) + foreach(_PYTHON_V ${_PYTHON${_PYTHON_FIND_MAJ}_VERSIONS}) + if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN) + list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V}) + endif() + endforeach() + endif() + unset(_PYTHON_FIND_MAJ_MIN) + unset(_PYTHON_FIND_MAJ) + else() + list(APPEND _Python_NAMES python${PythonInterp_FIND_VERSION}) + set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonInterp_FIND_VERSION}_VERSIONS}) + endif() +else() + set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS}) +endif() + +list(APPEND _Python_NAMES python) + +# Search for the current active python version first +find_program(PYTHON_EXECUTABLE NAMES ${_Python_NAMES}) + +# Set up the versions we know about, in the order we will search. Always add +# the user supplied additional versions to the front. +set(_Python_VERSIONS + ${Python_ADDITIONAL_VERSIONS} + ${_PYTHON_FIND_OTHER_VERSIONS} + ) + +unset(_PYTHON_FIND_OTHER_VERSIONS) +unset(_PYTHON1_VERSIONS) +unset(_PYTHON2_VERSIONS) +unset(_PYTHON3_VERSIONS) + +# Search for newest python version if python executable isn't found +if(NOT PYTHON_EXECUTABLE) + foreach(_CURRENT_VERSION ${_Python_VERSIONS}) + set(_Python_NAMES python${_CURRENT_VERSION}) + if(WIN32) + list(APPEND _Python_NAMES python) + endif() + find_program(PYTHON_EXECUTABLE + NAMES ${_Python_NAMES} + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath] + ) + endforeach() +endif() + +# determine python version string +if(PYTHON_EXECUTABLE) + execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c + "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))" + OUTPUT_VARIABLE _VERSION + RESULT_VARIABLE _PYTHON_VERSION_RESULT + ERROR_QUIET) + if(NOT _PYTHON_VERSION_RESULT) + string(REPLACE ";" "." PYTHON_VERSION_STRING "${_VERSION}") + list(GET _VERSION 0 PYTHON_VERSION_MAJOR) + list(GET _VERSION 1 PYTHON_VERSION_MINOR) + list(GET _VERSION 2 PYTHON_VERSION_PATCH) + if(PYTHON_VERSION_PATCH EQUAL 0) + # it's called "Python 2.7", not "2.7.0" + string(REGEX REPLACE "\\.0$" "" PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}") + endif() + else() + # sys.version predates sys.version_info, so use that + execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.version)" + OUTPUT_VARIABLE _VERSION + RESULT_VARIABLE _PYTHON_VERSION_RESULT + ERROR_QUIET) + if(NOT _PYTHON_VERSION_RESULT) + string(REGEX REPLACE " .*" "" PYTHON_VERSION_STRING "${_VERSION}") + string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON_VERSION_MAJOR "${PYTHON_VERSION_STRING}") + string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON_VERSION_MINOR "${PYTHON_VERSION_STRING}") + if(PYTHON_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+.*") + string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PYTHON_VERSION_PATCH "${PYTHON_VERSION_STRING}") + else() + set(PYTHON_VERSION_PATCH "0") + endif() + else() + # sys.version was first documented for Python 1.5, so assume + # this is older. + set(PYTHON_VERSION_STRING "1.4") + set(PYTHON_VERSION_MAJOR "1") + set(PYTHON_VERSION_MAJOR "4") + set(PYTHON_VERSION_MAJOR "0") + endif() + endif() + unset(_PYTHON_VERSION_RESULT) + unset(_VERSION) +endif() + +# handle the QUIETLY and REQUIRED arguments and set PYTHONINTERP_FOUND to TRUE if +# all listed variables are TRUE +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonInterp REQUIRED_VARS PYTHON_EXECUTABLE VERSION_VAR PYTHON_VERSION_STRING) + +mark_as_advanced(PYTHON_EXECUTABLE) diff --git a/libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake b/libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake new file mode 100644 index 0000000..c8d27f2 --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake @@ -0,0 +1,130 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake.in b/libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake.in new file mode 100644 index 0000000..69aa84e --- /dev/null +++ b/libbtbb-2015-10-R1/cmake/modules/GetGitRevisionDescription.cmake.in @@ -0,0 +1,39 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") + configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + set(HEAD_HASH "${HEAD_REF}") + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) + string(SUBSTRING ${HEAD_HASH} 0 7 HEAD_HASH) +endif() diff --git a/libbtbb-2015-10-R1/lib/CMakeLists.txt b/libbtbb-2015-10-R1/lib/CMakeLists.txt new file mode 100644 index 0000000..6fcebf5 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# Copyright 2013 Dominic Spill +# +# This file is part of Libbtbb. +# +# 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, 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include(GNUInstallDirs) + +# Based heavily upon the hackrf cmake setup. + +project(libbtbb C) +set(PACKAGE libbtbb) + +add_subdirectory(src) + +CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/libbtbb.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/libbtbb.pc +@ONLY) + +INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/libbtbb.pc + DESTINATION lib${LIB_SUFFIX}/pkgconfig +) diff --git a/libbtbb-2015-10-R1/lib/libbtbb.pc.in b/libbtbb-2015-10-R1/lib/libbtbb.pc.in new file mode 100644 index 0000000..05d58f7 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/libbtbb.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: Bluetooth Baseband Library +Description: C Utility Library +Version: @VERSION@ +Cflags: -I${includedir}/ @BTBB_PC_CFLAGS@ +Libs: -L${libdir} -lbtbb +Libs.private: @BTBB_PC_LIBS@ diff --git a/libbtbb-2015-10-R1/lib/src/CMakeLists.txt b/libbtbb-2015-10-R1/lib/src/CMakeLists.txt new file mode 100644 index 0000000..2be9c5f --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/CMakeLists.txt @@ -0,0 +1,105 @@ +# +# This file is part of Libbtbb. +# +# 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, 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# +# Based slightly upon the hackrf cmake setup. + +# FIXME Set static release version here to avoid pulling from git +set(RELEASE "") +set(DIRTY_FLAG "") + +if ( "${RELEASE}" STREQUAL "" ) + # automatic git version when working out of git + include(GetGitRevisionDescription) + get_git_head_revision(GIT_REFSPEC RELEASE) + + execute_process(COMMAND git status -s --untracked-files=no OUTPUT_VARIABLE DIRTY) + if ( NOT "${DIRTY}" STREQUAL "" ) + set(DIRTY_FLAG "*") + endif() +endif() + +add_definitions( -DRELEASE="${RELEASE}${DIRTY_FLAG}" ) + +# Source +set(c_sources ${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_packet.c + ${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_piconet.c + ${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_le_packet.c + ${CMAKE_CURRENT_SOURCE_DIR}/pcap.c + ${CMAKE_CURRENT_SOURCE_DIR}/pcapng.c + ${CMAKE_CURRENT_SOURCE_DIR}/pcapng-bt.c + CACHE INTERNAL "List of C sources") +set(c_headers ${CMAKE_CURRENT_SOURCE_DIR}/btbb.h + CACHE INTERNAL "List of C headers") + +# For cygwin just force UNIX OFF and WIN32 ON +if( ${CYGWIN} ) + SET(UNIX OFF) + SET(WIN32 ON) +endif( ${CYGWIN} ) + +# FIXME: This may be a hack +# perhaps there should be separate libbtbb and libbtbb-static targets? +if( ${WIN32} ) + # Static library + add_library(btbb STATIC ${c_sources}) + set_target_properties(btbb PROPERTIES OUTPUT_NAME "btbb_static") +else() + # Dynamic library + add_library(btbb SHARED ${c_sources}) + set_target_properties(btbb PROPERTIES VERSION ${MAJOR_VERSION}.${MINOR_VERSION} SOVERSION 0) +endif() + +set_target_properties(btbb PROPERTIES CLEAN_DIRECT_OUTPUT 1) + +# PCAP Support +if( (NOT DEFINED USE_PCAP) OR USE_PCAP ) + find_package(PCAP) + + if( USE_PCAP AND NOT ${PCAP_FOUND} ) + message( FATAL_ERROR + "Cannot find libpcap, which is required for USE_PCAP") + endif() + + if( ${PCAP_FOUND} ) + include_directories(${PCAP_INCLUDE_DIRS}) + target_link_libraries(btbb ${PCAP_LIBRARIES}) + add_definitions( -DENABLE_PCAP ) + endif( ${PCAP_FOUND} ) +endif( (NOT DEFINED USE_PCAP) OR USE_PCAP ) + +if( ${UNIX} ) + install(TARGETS btbb + LIBRARY DESTINATION lib${LIB_SUFFIX} + COMPONENT sharedlibs + ) + install(FILES ${c_headers} + DESTINATION include + COMPONENT headers + ) +endif( ${UNIX} ) + +if( ${WIN32} ) + install(TARGETS btbb + DESTINATION bin + COMPONENT staticlibs + ) + install(FILES ${c_headers} + DESTINATION include + COMPONENT headers + ) +endif( ${WIN32} ) diff --git a/libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.c b/libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.c new file mode 100644 index 0000000..579a7ae --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.c @@ -0,0 +1,607 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2012 Mike Ryan, Dominic Spill, Michael Ossmann + * Copyright 2005, 2006 Free Software Foundation, Inc. + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "btbb.h" +#include "bluetooth_le_packet.h" +#include +#include + +/* string representations of advertising packet type */ +static const char *ADV_TYPE_NAMES[] = { + "ADV_IND", "ADV_DIRECT_IND", "ADV_NONCONN_IND", "SCAN_REQ", + "SCAN_RSP", "CONNECT_REQ", "ADV_SCAN_IND", +}; + +/* source clock accuracy in a connect packet */ +static const char *CONNECT_SCA[] = { + "251 ppm to 500 ppm", "151 ppm to 250 ppm", "101 ppm to 150 ppm", + "76 ppm to 100 ppm", "51 ppm to 75 ppm", "31 ppm to 50 ppm", + "21 ppm to 30 ppm", "0 ppm to 20 ppm", +}; + +// count of objects in an array, shamelessly stolen from Chrome +#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) + +static uint8_t count_bits(uint32_t n) +{ + uint8_t i = 0; + for (i = 0; n != 0; i++) + n &= n - 1; + return i; +} + +static int aa_access_channel_off_by_one(const uint32_t aa) { + int retval = 0; + if(count_bits(aa ^ LE_ADV_AA) == 1) { + retval = 1; + } + return retval; +} + +/* + * A helper function for filtering bogus packets on data channels. + * + * If a candidate capture packet is random noise we would expect its + * Access Address to be a randomly distributed 32-bit number. An + * exhaustive software analysis reveals that of 4294967296 possible + * 32-bit Access Address values, 2900629660 (67.5%) are acceptable and + * 1394337636 (32.5%) are invalid. This function will identify which + * category a candidate Access Address falls into by returning the + * number of offenses contained. + * + * Refer to BT 4.x, Vol 6, Par B, Section 2.1.2. + * + * The Access Address in data channel packets meet the + * following requirements: + * - It shall have no more than six consecutive zeros or ones. + * - It shall not be the advertising channel packets’ Access Address. + * - It shall not be a sequence that differs from the advertising channel packets’ + * Access Address by only one bit. + * - It shall not have all four octets equal. + * - It shall have no more than 24 transitions. + * - It shall have a minimum of two transitions in the most significant six bits. + */ +static int aa_data_channel_offenses(const uint32_t aa) { + int retval = 0, transitions = 0; + unsigned shift, odd = (unsigned) (aa & 1); + uint8_t aab3, aab2, aab1, aab0 = (uint8_t) (aa & 0xff); + + const uint8_t EIGHT_BIT_TRANSITIONS_EVEN[256] = { + 0, 2, 2, 2, 2, 4, 2, 2, 2, 4, 4, 4, 2, 4, 2, 2, + 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, + 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4, + 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, + 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4, + 4, 6, 6, 6, 6, 8, 6, 6, 4, 6, 6, 6, 4, 6, 4, 4, + 2, 4, 4, 4, 4, 6, 4, 4, 4, 6, 6, 6, 4, 6, 4, 4, + 2, 4, 4, 4, 4, 6, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, + 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3, + 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3, + 3, 5, 5, 5, 5, 7, 5, 5, 5, 7, 7, 7, 5, 7, 5, 5, + 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3, + 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3, + 3, 5, 5, 5, 5, 7, 5, 5, 3, 5, 5, 5, 3, 5, 3, 3, + 1, 3, 3, 3, 3, 5, 3, 3, 3, 5, 5, 5, 3, 5, 3, 3, + 1, 3, 3, 3, 3, 5, 3, 3, 1, 3, 3, 3, 1, 3, 1, 1 + }; + + const uint8_t EIGHT_BIT_TRANSITIONS_ODD[256] = { + 1, 1, 3, 1, 3, 3, 3, 1, 3, 3, 5, 3, 3, 3, 3, 1, + 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1, + 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3, + 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1, + 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3, + 5, 5, 7, 5, 7, 7, 7, 5, 5, 5, 7, 5, 5, 5, 5, 3, + 3, 3, 5, 3, 5, 5, 5, 3, 5, 5, 7, 5, 5, 5, 5, 3, + 3, 3, 5, 3, 5, 5, 5, 3, 3, 3, 5, 3, 3, 3, 3, 1, + 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2, + 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2, + 4, 4, 6, 4, 6, 6, 6, 4, 6, 6, 8, 6, 6, 6, 6, 4, + 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2, + 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2, + 4, 4, 6, 4, 6, 6, 6, 4, 4, 4, 6, 4, 4, 4, 4, 2, + 2, 2, 4, 2, 4, 4, 4, 2, 4, 4, 6, 4, 4, 4, 4, 2, + 2, 2, 4, 2, 4, 4, 4, 2, 2, 2, 4, 2, 2, 2, 2, 0 + }; + + transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab0] : EIGHT_BIT_TRANSITIONS_EVEN[aab0] ); + odd = (unsigned) (aab0 & 0x80); + aab1 = (uint8_t) (aa >> 8); + transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab1] : EIGHT_BIT_TRANSITIONS_EVEN[aab1] ); + odd = (unsigned) (aab1 & 0x80); + aab2 = (uint8_t) (aa >> 16); + transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab2] : EIGHT_BIT_TRANSITIONS_EVEN[aab2] ); + odd = (unsigned) (aab2 & 0x80); + aab3 = (uint8_t) (aa >> 24); + transitions += (odd ? EIGHT_BIT_TRANSITIONS_ODD[aab3] : EIGHT_BIT_TRANSITIONS_EVEN[aab3] ); + + /* consider excessive transitions as offenses */ + if (transitions > 24) { + retval += (transitions - 24); + } + + const uint8_t AA_MSB6_ALLOWED[64] = { + 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0 + }; + + /* consider excessive transitions in the 6 MSBs as an offense */ + retval += (1 - AA_MSB6_ALLOWED[aab3>>2]); + + /* consider all bytes as being equal an offense */ + retval += (((aab0 == aab1) && (aab0 == aab2) && (aab0 == aab3)) ? 1 : 0); + + /* access-channel address and off-by-ones are illegal */ + retval += ((aa == LE_ADV_AA) ? 1 : 0); + retval += aa_access_channel_off_by_one(aa); + + /* inspect nibble triples for insufficient bit transitions */ + for(shift=0; shift<=20; shift+=4) { + uint16_t twelvebits = (uint16_t) ((aa >> shift) & 0xfff); + switch( twelvebits ) { + /* seven consecutive zeroes */ + case 0x080: case 0x180: case 0x280: case 0x380: case 0x480: + case 0x580: case 0x680: case 0x780: case 0x880: case 0x980: + case 0xa80: case 0xb80: case 0xc80: case 0xd80: case 0xe80: + case 0xf80: case 0x101: case 0x301: case 0x501: case 0x701: + case 0x901: case 0xb01: case 0xd01: case 0xf01: case 0x202: + case 0x602: case 0xa02: case 0xe02: case 0x203: case 0x603: + case 0xa03: case 0xe03: case 0x404: case 0xc04: case 0x405: + case 0xc05: case 0x406: case 0xc06: case 0x407: case 0xc07: + case 0x808: case 0x809: case 0x80a: case 0x80b: case 0x80c: + case 0x80d: case 0x80e: case 0x80f: case 0x010: case 0x011: + case 0x012: case 0x013: case 0x014: case 0x015: case 0x016: + case 0x017: case 0x018: case 0x019: case 0x01a: case 0x01b: + case 0x01c: case 0x01d: case 0x01e: case 0x01f: + /* eight consecutive zeroes */ + case 0x100: case 0x300: case 0x500: case 0x700: case 0x900: + case 0xb00: case 0xd00: case 0xf00: case 0x201: case 0x601: + case 0xa01: case 0xe01: case 0x402: case 0xc02: case 0x403: + case 0xc03: case 0x804: case 0x805: case 0x806: case 0x807: + case 0x008: case 0x009: case 0x00a: case 0x00b: case 0x00c: + case 0x00d: case 0x00e: case 0x00f: + /* nine consecutive zeroes */ + case 0xe00: case 0xc01: case 0x802: case 0x803: case 0x004: + case 0x005: case 0x006: case 0x007: + /* ten consecutive zeroes */ + case 0x400: case 0xc00: case 0x801: case 0x002: case 0x003: + /* eleven consecutive zeroes */ + case 0x800: case 0x001: + /* twelve consecutive zeroes */ + case 0x000: + /* seven consecutive ones */ + case 0x07f: case 0x0fe: case 0x2fe: case 0x4fe: case 0x6fe: + case 0x8fe: case 0xafe: case 0xcfe: case 0xefe: case 0x1fc: + case 0x5fc: case 0x9fc: case 0xdfc: case 0x1fd: case 0x5fd: + case 0x9fd: case 0xdfd: case 0x3f8: case 0xbf8: case 0x3f9: + case 0xbf9: case 0x3fa: case 0xbfa: case 0x3fb: case 0xbfb: + case 0x7f4: case 0x7f5: case 0x7f6: case 0x7f7: case 0xfe0: + /* eight consecutive ones */ + case 0x0ff: case 0x2ff: case 0x4ff: case 0x6ff: case 0x8ff: + case 0xaff: case 0xcff: case 0xeff: case 0x1fe: case 0x5fe: + case 0x9fe: case 0xdfe: case 0x3fc: case 0xbfc: case 0x3fd: + case 0xbfd: case 0x7f8: case 0x7f9: case 0x7fa: case 0x7fb: + case 0xff0: case 0xff1: case 0xff2: case 0xff3: case 0xff4: + case 0xff5: case 0xff6: case 0xff7: + /* nine consecutive ones */ + case 0x1ff: case 0x5ff: case 0x9ff: case 0xdff: case 0x3fe: + case 0xbfe: case 0x7fc: case 0x7fd: case 0xff8: case 0xff9: + case 0xffa: case 0xffb: + /* ten consecutive ones */ + case 0x3ff: case 0xbff: case 0x7fe: case 0xffc: case 0xffd: + /* eleven consecutive ones */ + case 0x7ff: case 0xffe: + /* all ones */ + case 0xfff: + retval++; + break; + default: + break; + } + } + + return retval; +} + +lell_packet * +lell_packet_new(void) +{ + lell_packet *pkt = (lell_packet *)calloc(1, sizeof(lell_packet)); + pkt->refcount = 1; + return pkt; +} + +void +lell_packet_ref(lell_packet *pkt) +{ + pkt->refcount++; +} + +void +lell_packet_unref(lell_packet *pkt) +{ + pkt->refcount--; + if (pkt->refcount == 0) + free(pkt); +} + +static uint8_t le_channel_index(uint16_t phys_channel) { + uint8_t ret; + if (phys_channel == 2402) { + ret = 37; + } else if (phys_channel < 2426) { // 0 - 10 + ret = (phys_channel - 2404) / 2; + } else if (phys_channel == 2426) { + ret = 38; + } else if (phys_channel < 2480) { // 11 - 36 + ret = 11 + (phys_channel - 2428) / 2; + } else { + ret = 39; + } + return ret; +} + +void lell_allocate_and_decode(const uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, lell_packet **pkt) +{ + *pkt = lell_packet_new( ); + memcpy((*pkt)->symbols, stream, MAX_LE_SYMBOLS); + + (*pkt)->channel_idx = le_channel_index(phys_channel); + (*pkt)->channel_k = (phys_channel-2402)/2; + (*pkt)->clk100ns = clk100ns; + + (*pkt)->access_address = 0; + (*pkt)->access_address |= (*pkt)->symbols[0]; + (*pkt)->access_address |= (*pkt)->symbols[1] << 8; + (*pkt)->access_address |= (*pkt)->symbols[2] << 16; + (*pkt)->access_address |= (*pkt)->symbols[3] << 24; + + if (lell_packet_is_data(*pkt)) { + // data PDU + (*pkt)->length = (*pkt)->symbols[5] & 0x1f; + (*pkt)->access_address_offenses = aa_data_channel_offenses((*pkt)->access_address); + (*pkt)->flags.as_bits.access_address_ok = (*pkt)->access_address_offenses ? 0 : 1; + } else { + // advertising PDU + (*pkt)->length = (*pkt)->symbols[5] & 0x3f; + (*pkt)->adv_type = (*pkt)->symbols[4] & 0xf; + (*pkt)->adv_tx_add = (*pkt)->symbols[4] & 0x40 ? 1 : 0; + (*pkt)->adv_rx_add = (*pkt)->symbols[4] & 0x80 ? 1 : 0; + (*pkt)->flags.as_bits.access_address_ok = ((*pkt)->access_address == 0x8e89bed6); + (*pkt)->access_address_offenses = (*pkt)->flags.as_bits.access_address_ok ? 0 : + (aa_access_channel_off_by_one((*pkt)->access_address) ? 1 : 32); + } +} + +unsigned lell_packet_is_data(const lell_packet *pkt) +{ + return (unsigned) (pkt->channel_idx < 37); +} + +uint32_t lell_get_access_address(const lell_packet *pkt) +{ + return pkt->access_address; +} + +unsigned lell_get_access_address_offenses(const lell_packet *pkt) +{ + return pkt->access_address_offenses; +} + +unsigned lell_get_channel_index(const lell_packet *pkt) +{ + return pkt->channel_idx; +} + +unsigned lell_get_channel_k(const lell_packet *pkt) +{ + return pkt->channel_k; +} + +const char * lell_get_adv_type_str(const lell_packet *pkt) +{ + if (lell_packet_is_data(pkt)) + return NULL; + if (pkt->adv_type < COUNT_OF(ADV_TYPE_NAMES)) + return ADV_TYPE_NAMES[pkt->adv_type]; + return "UNKNOWN"; +} + +static void _dump_addr(const char *name, const uint8_t *buf, int offset, int random) { + int i; + printf(" %s%02x", name, buf[offset+5]); + for (i = 4; i >= 0; --i) + printf(":%02x", buf[offset+i]); + printf(" (%s)\n", random ? "random" : "public"); +} + +static void _dump_8(const char *name, const uint8_t *buf, int offset) { + printf(" %s%02x (%d)\n", name, buf[offset], buf[offset]); +} + +static void _dump_16(const char *name, const uint8_t *buf, int offset) { + uint16_t val = buf[offset+1] << 8 | buf[offset]; + printf(" %s%04x (%d)\n", name, val, val); +} + +static void _dump_24(char *name, const uint8_t *buf, int offset) { + uint32_t val = buf[offset+2] << 16 | buf[offset+1] << 8 | buf[offset]; + printf(" %s%06x\n", name, val); +} + +static void _dump_32(const char *name, const uint8_t *buf, int offset) { + uint32_t val = buf[offset+3] << 24 | + buf[offset+2] << 16 | + buf[offset+1] << 8 | + buf[offset+0]; + printf(" %s%08x\n", name, val); +} + +static void _dump_uuid(const uint8_t *uuid) { + int i; + for (i = 0; i < 4; ++i) + printf("%02x", uuid[i]); + printf("-"); + for (i = 4; i < 6; ++i) + printf("%02x", uuid[i]); + printf("-"); + for (i = 6; i < 8; ++i) + printf("%02x", uuid[i]); + printf("-"); + for (i = 8; i < 10; ++i) + printf("%02x", uuid[i]); + printf("-"); + for (i = 10; i < 16; ++i) + printf("%02x", uuid[i]); +} + +// Refer to pg 1735 of Bluetooth Core Spec 4.0 +static void _dump_scan_rsp_data(const uint8_t *buf, int len) { + int pos = 0; + int sublen, i; + uint8_t type; + uint16_t val; + char *cval; + + while (pos < len) { + sublen = buf[pos]; + ++pos; + if (pos + sublen > len) { + printf("Error: attempt to read past end of buffer (%d + %d > %d)\n", pos, sublen, len); + return; + } + if (sublen == 0) { + printf("Early return due to 0 length\n"); + return; + } + type = buf[pos]; + printf(" Type %02x", type); + switch (type) { + case 0x01: + printf(" (Flags)\n"); + printf(" "); + for (i = 0; i < 8; ++i) + printf("%d", buf[pos+1] & (1 << (7-i)) ? 1 : 0); + printf("\n"); + break; + case 0x06: + printf(" (128-bit Service UUIDs, more available)\n"); + goto print128; + case 0x07: + printf(" (128-bit Service UUIDs)\n"); +print128: + if ((sublen - 1) % 16 == 0) { + uint8_t uuid[16]; + for (i = 0; i < sublen - 1; ++i) { + uuid[15 - (i % 16)] = buf[pos+1+i]; + if ((i & 15) == 15) { + printf(" "); + _dump_uuid(uuid); + printf("\n"); + } + } + } + else { + printf("Wrong length (%d, must be divisible by 16)\n", sublen-1); + } + break; + case 0x09: + printf(" (Complete Local Name)\n"); + printf(" "); + for (i = 1; i < sublen; ++i) + printf("%c", isprint(buf[pos+i]) ? buf[pos+i] : '.'); + printf("\n"); + break; + case 0x0a: + printf(" (Tx Power Level)\n"); + printf(" "); + if (sublen-1 == 1) { + cval = (char *)&buf[pos+1]; + printf("%d dBm\n", *cval); + } else { + printf("Wrong length (%d, should be 1)\n", sublen-1); + } + break; + case 0x12: + printf(" (Slave Connection Interval Range)\n"); + printf(" "); + if (sublen-1 == 4) { + val = (buf[pos+2] << 8) | buf[pos+1]; + printf("(%0.2f, ", val * 1.25); + val = (buf[pos+4] << 8) | buf[pos+3]; + printf("%0.2f) ms\n", val * 1.25); + } + else { + printf("Wrong length (%d, should be 4)\n", sublen-1); + } + break; + case 0x16: + printf(" (Service Data)\n"); + printf(" "); + if (sublen-1 >= 2) { + val = (buf[pos+2] << 8) | buf[pos+1]; + printf("UUID: %02x", val); + if (sublen-1 > 2) { + printf(", Additional:"); + for (i = 3; i < sublen; ++i) + printf(" %02x", buf[pos+i]); + } + printf("\n"); + } + else { + printf("Wrong length (%d, should be >= 2)\n", sublen-1); + } + break; + default: + printf("\n"); + printf(" "); + for (i = 1; i < sublen; ++i) + printf(" %02x", buf[pos+i]); + printf("\n"); + } + pos += sublen; + } +} + +void lell_print(const lell_packet *pkt) +{ + int i, opcode; + if (lell_packet_is_data(pkt)) { + int llid = pkt->symbols[4] & 0x3; + static const char *llid_str[] = { + "Reserved", + "LL Data PDU / empty or L2CAP continuation", + "LL Data PDU / L2CAP start", + "LL Control PDU", + }; + + printf("Data / AA %08x (%s) / %2d bytes\n", pkt->access_address, + pkt->flags.as_bits.access_address_ok ? "valid" : "invalid", + pkt->length); + printf(" Channel Index: %d\n", pkt->channel_idx); + printf(" LLID: %d / %s\n", llid, llid_str[llid]); + printf(" NESN: %d SN: %d MD: %d\n", (pkt->symbols[4] >> 2) & 1, + (pkt->symbols[4] >> 3) & 1, + (pkt->symbols[4] >> 4) & 1); + switch (llid) { + case 3: // LL Control PDU + opcode = pkt->symbols[6]; + static const char *opcode_str[] = { + "LL_CONNECTION_UPDATE_REQ", + "LL_CHANNEL_MAP_REQ", + "LL_TERMINATE_IND", + "LL_ENC_REQ", + "LL_ENC_RSP", + "LL_START_ENC_REQ", + "LL_START_ENC_RSP", + "LL_UNKNOWN_RSP", + "LL_FEATURE_REQ", + "LL_FEATURE_RSP", + "LL_PAUSE_ENC_REQ", + "LL_PAUSE_ENC_RSP", + "LL_VERSION_IND", + "LL_REJECT_IND", + "LL_SLAVE_FEATURE_REQ", + "LL_CONNECTION_PARAM_REQ", + "LL_CONNECTION_PARAM_RSP", + "LL_REJECT_IND_EXT", + "LL_PING_REQ", + "LL_PING_RSP", + "Reserved for Future Use", + }; + printf(" Opcode: %d / %s\n", opcode, opcode_str[(opcode<0x14)?opcode:0x14]); + break; + default: + break; + } + } else { + printf("Advertising / AA %08x (%s)/ %2d bytes\n", pkt->access_address, + pkt->flags.as_bits.access_address_ok ? "valid" : "invalid", + pkt->length); + printf(" Channel Index: %d\n", pkt->channel_idx); + printf(" Type: %s\n", lell_get_adv_type_str(pkt)); + + switch(pkt->adv_type) { + case ADV_IND: + _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add); + if (pkt->length-6 > 0) { + printf(" AdvData:"); + for (i = 0; i < pkt->length - 6; ++i) + printf(" %02x", pkt->symbols[12+i]); + printf("\n"); + _dump_scan_rsp_data(&pkt->symbols[12], pkt->length-6); + } + break; + case SCAN_REQ: + _dump_addr("ScanA: ", pkt->symbols, 6, pkt->adv_tx_add); + _dump_addr("AdvA: ", pkt->symbols, 12, pkt->adv_rx_add); + break; + case SCAN_RSP: + _dump_addr("AdvA: ", pkt->symbols, 6, pkt->adv_tx_add); + printf(" ScanRspData:"); + for (i = 0; i < pkt->length - 6; ++i) + printf(" %02x", pkt->symbols[12+i]); + printf("\n"); + _dump_scan_rsp_data(&pkt->symbols[12], pkt->length-6); + break; + case CONNECT_REQ: + _dump_addr("InitA: ", pkt->symbols, 6, pkt->adv_tx_add); + _dump_addr("AdvA: ", pkt->symbols, 12, pkt->adv_rx_add); + _dump_32("AA: ", pkt->symbols, 18); + _dump_24("CRCInit: ", pkt->symbols, 22); + _dump_8("WinSize: ", pkt->symbols, 25); + _dump_16("WinOffset: ", pkt->symbols, 26); + _dump_16("Interval: ", pkt->symbols, 28); + _dump_16("Latency: ", pkt->symbols, 30); + _dump_16("Timeout: ", pkt->symbols, 32); + + printf(" ChM:"); + for (i = 0; i < 5; ++i) + printf(" %02x", pkt->symbols[34+i]); + printf("\n"); + + printf(" Hop: %d\n", pkt->symbols[39] & 0x1f); + printf(" SCA: %d, %s\n", + pkt->symbols[39] >> 5, + CONNECT_SCA[pkt->symbols[39] >> 5]); + break; + } + } + + printf("\n"); + printf(" Data: "); + for (i = 6; i < 6 + pkt->length; ++i) + printf(" %02x", pkt->symbols[i]); + printf("\n"); + + printf(" CRC: "); + for (i = 0; i < 3; ++i) + printf(" %02x", pkt->symbols[6 + pkt->length + i]); + printf("\n"); +} diff --git a/libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.h b/libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.h new file mode 100644 index 0000000..a16fb0b --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/bluetooth_le_packet.h @@ -0,0 +1,74 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2012 Mike Ryan, Dominic Spill, Michael Ossmann + * Copyright 2005, 2006 Free Software Foundation, Inc. + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_BLUETOOTH_LE_PACKET_H +#define INCLUDED_BLUETOOTH_LE_PACKET_H + +#include +#include +#include + +#define MAX_LE_SYMBOLS 64 + +#define LE_ADV_AA 0x8E89BED6 + +#define ADV_IND 0 +#define ADV_DIRECT_IND 1 +#define ADV_NONCONN_IND 2 +#define SCAN_REQ 3 +#define SCAN_RSP 4 +#define CONNECT_REQ 5 +#define ADV_SCAN_IND 6 + +struct lell_packet { + // raw unwhitened bytes of packet, including access address + uint8_t symbols[MAX_LE_SYMBOLS]; + + uint32_t access_address; + + // channel index + uint8_t channel_idx; + uint8_t channel_k; + + // number of symbols + int length; + + uint32_t clk100ns; + + // advertising packet header info + uint8_t adv_type; + int adv_tx_add; + int adv_rx_add; + + unsigned access_address_offenses; + uint32_t refcount; + + /* flags */ + union { + struct { + uint32_t access_address_ok : 1; + } as_bits; + uint32_t as_word; + } flags; +}; + +#endif /* INCLUDED_BLUETOOTH_LE_PACKET_H */ diff --git a/libbtbb-2015-10-R1/lib/src/bluetooth_packet.c b/libbtbb-2015-10-R1/lib/src/bluetooth_packet.c new file mode 100644 index 0000000..f070ad7 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/bluetooth_packet.c @@ -0,0 +1,1421 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "bluetooth_packet.h" +#include "uthash.h" +#include "sw_check_tables.h" + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +/* Maximum number of AC errors supported by library. Caller may + * specify any value <= AC_ERROR_LIMIT in btbb_init(). */ +#define AC_ERROR_LIMIT 5 + +/* maximum number of bit errors for known syncwords */ +#define MAX_SYNCWORD_ERRS 5 + +/* maximum number of bit errors in */ +#define MAX_BARKER_ERRORS 1 + +/* default codeword modified for PN sequence and barker code */ +#define DEFAULT_CODEWORD 0xb0000002c7820e7eULL + +/* Default access code, used for calculating syndromes */ +#define DEFAULT_AC 0xcc7b7268ff614e1bULL + +/* index into whitening data array */ +static const uint8_t INDICES[] = {99, 85, 17, 50, 102, 58, 108, 45, 92, 62, 32, 118, 88, 11, 80, 2, 37, 69, 55, 8, 20, 40, 74, 114, 15, 106, 30, 78, 53, 72, 28, 26, 68, 7, 39, 113, 105, 77, 71, 25, 84, 49, 57, 44, 61, 117, 10, 1, 123, 124, 22, 125, 111, 23, 42, 126, 6, 112, 76, 24, 48, 43, 116, 0}; + +/* whitening data */ +static const uint8_t WHITENING_DATA[] = {1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1}; + +/* lookup table for barker code hamming distance */ +static const uint8_t BARKER_DISTANCE[] = { + 3,3,3,2,3,2,2,1,2,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,1,2,2,3,2,3,3,3, + 3,2,2,1,2,1,1,0,3,3,3,2,3,2,2,1,3,3,3,2,3,2,2,1,2,3,3,3,3,3,3,2, + 2,3,3,3,3,3,3,2,1,2,2,3,2,3,3,3,1,2,2,3,2,3,3,3,0,1,1,2,1,2,2,3, + 3,3,3,2,3,2,2,1,2,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,1,2,2,3,2,3,3,3}; + +/* string representations of packet type */ +static const char * const TYPE_NAMES[] = { + "NULL", "POLL", "FHS", "DM1", "DH1/2-DH1", "HV1", "HV2/2-EV3", "HV3/EV3/3-EV3", + "DV/3-DH1", "AUX1", "DM3/2-DH3", "DH3/3-DH3", "EV4/2-EV5", "EV5/3-EV5", "DM5/2-DH5", "DH5/3-DH5" +}; + +/* + * generator matrix for sync word (64,30) linear block code + * based on polynomial 0260534236651 + * thanks to http://www.ee.unb.ca/cgi-bin/tervo/polygen.pl + * modified for barker code + */ +static const uint64_t sw_matrix[] = { + 0xfe000002a0d1c014ULL, 0x01000003f0b9201fULL, 0x008000033ae40edbULL, 0x004000035fca99b9ULL, + 0x002000036d5dd208ULL, 0x00100001b6aee904ULL, 0x00080000db577482ULL, 0x000400006dabba41ULL, + 0x00020002f46d43f4ULL, 0x000100017a36a1faULL, 0x00008000bd1b50fdULL, 0x000040029c3536aaULL, + 0x000020014e1a9b55ULL, 0x0000100265b5d37eULL, 0x0000080132dae9bfULL, 0x000004025bd5ea0bULL, + 0x00000203ef526bd1ULL, 0x000001033511ab3cULL, 0x000000819a88d59eULL, 0x00000040cd446acfULL, + 0x00000022a41aabb3ULL, 0x0000001390b5cb0dULL, 0x0000000b0ae27b52ULL, 0x0000000585713da9ULL}; + +static const uint64_t barker_correct[] = { + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, 0x4e00000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, + 0xb000000000000000ULL, 0xb000000000000000ULL, 0xb000000000000000ULL, 0x4e00000000000000ULL}; + +static const uint64_t pn = 0x83848D96BBCC54FCULL; + +static const uint16_t fec23_gen_matrix[] = { + 0x2c01, 0x5802, 0x1c04, 0x3808, 0x7010, + 0x4c20, 0x3440, 0x6880, 0x7d00, 0x5600}; + +typedef struct { + uint64_t syndrome; /* key */ + uint64_t error; + UT_hash_handle hh; +} syndrome_struct; + +static syndrome_struct *syndrome_map = NULL; + +static void add_syndrome(uint64_t syndrome, uint64_t error) +{ + syndrome_struct *s; + s = malloc(sizeof(syndrome_struct)); + s->syndrome = syndrome; + s->error = error; + + HASH_ADD(hh, syndrome_map, syndrome, 8, s); +} + +static syndrome_struct *find_syndrome(uint64_t syndrome) +{ + syndrome_struct *s; + + HASH_FIND(hh, syndrome_map, &syndrome, 8, s); + return s; +} + +static uint64_t gen_syndrome(uint64_t codeword) +{ + uint64_t syndrome = codeword & 0xffffffff; + codeword >>= 32; + syndrome ^= sw_check_table4[codeword & 0xff]; + codeword >>= 8; + syndrome ^= sw_check_table5[codeword & 0xff]; + codeword >>= 8; + syndrome ^= sw_check_table6[codeword & 0xff]; + codeword >>= 8; + syndrome ^= sw_check_table7[codeword & 0xff]; + return syndrome; +} + +static void cycle(uint64_t error, int start, int depth, uint64_t codeword) +{ + uint64_t new_error, syndrome, base; + int i; + base = 1; + depth -= 1; + for (i = start; i < 58; i++) + { + new_error = (base << i); + new_error |= error; + if (depth) + cycle(new_error, i + 1, depth, codeword); + else { + syndrome = gen_syndrome(codeword ^ new_error); + add_syndrome(syndrome, new_error); + } + } +} + +static void gen_syndrome_map(int bit_errors) +{ + int i; + for(i = 1; i <= bit_errors; i++) + cycle(0, 0, i, DEFAULT_AC); +} + +/* Generate Sync Word from an LAP */ +uint64_t btbb_gen_syncword(const int LAP) +{ + int i; + uint64_t codeword = DEFAULT_CODEWORD; + + /* the sync word generated is in host order, not air order */ + for (i = 0; i < 24; i++) + if (LAP & (0x800000 >> i)) + codeword ^= sw_matrix[i]; + + return codeword; +} + +static void init_packet(btbb_packet *pkt, uint32_t lap, uint8_t ac_errors) +{ + pkt->LAP = lap; + pkt->ac_errors = ac_errors; + + pkt->flags = 0; + btbb_packet_set_flag(pkt, BTBB_WHITENED, 1); +} + +/* Convert some number of bits of an air order array to a host order integer */ +static uint8_t air_to_host8(const char *air_order, const int bits) +{ + int i; + uint8_t host_order = 0; + for (i = 0; i < bits; i++) + host_order |= ((uint8_t)air_order[i] << i); + return host_order; +} +static uint16_t air_to_host16(const char *air_order, const int bits) +{ + int i; + uint16_t host_order = 0; + for (i = 0; i < bits; i++) + host_order |= ((uint16_t)air_order[i] << i); + return host_order; +} +static uint32_t air_to_host32(const char *air_order, const int bits) +{ + int i; + uint32_t host_order = 0; + for (i = 0; i < bits; i++) + host_order |= ((uint32_t)air_order[i] << i); + return host_order; +} +static uint64_t air_to_host64(const char *air_order, const int bits) +{ + int i; + uint64_t host_order = 0; + for (i = 0; i < bits; i++) + host_order |= ((uint64_t)air_order[i] << i); + return host_order; +} + +///* Convert some number of bits in a host order integer to an air order array */ +//static void host_to_air(const uint8_t host_order, char *air_order, const int bits) +//{ +// int i; +// for (i = 0; i < bits; i++) +// air_order[i] = (host_order >> i) & 0x01; +//} + +/* count the number of 1 bits in a uint64_t */ +static uint8_t count_bits(uint64_t n) +{ +#ifdef __GNUC__ + return (uint8_t) __builtin_popcountll (n); +#else + uint8_t i = 0; + for (i = 0; n != 0; i++) + n &= n - 1; + return i; +#endif +} + +#ifndef RELEASE +#define RELEASE "unknown" +#endif +char *btbb_get_release(void) { + return RELEASE; +} + +#ifndef VERSION +#define VERSION "unknown" +#endif +char *btbb_get_version(void) { + return VERSION; +} + +int btbb_init(int max_ac_errors) +{ + /* Sanity check max_ac_errors. */ + if ( (max_ac_errors < 0) || (max_ac_errors > AC_ERROR_LIMIT) ) { + fprintf(stderr, "%s: max_ac_errors out of range\n", + __FUNCTION__); + return -1; + } + + if ((syndrome_map == NULL) && (max_ac_errors)) + gen_syndrome_map(max_ac_errors); + + return 0; +} + +btbb_packet * +btbb_packet_new(void) +{ + btbb_packet *pkt = (btbb_packet *)calloc(1, sizeof(btbb_packet)); + if(pkt) + pkt->refcount = 1; + else + fprintf(stderr, "Unable to allocate packet"); + return pkt; +} + +void +btbb_packet_ref(btbb_packet *pkt) +{ + pkt->refcount++; +} + +void +btbb_packet_unref(btbb_packet *pkt) +{ + pkt->refcount--; + if (pkt->refcount == 0) + free(pkt); +} + +uint32_t btbb_packet_get_lap(const btbb_packet *pkt) +{ + return pkt->LAP; +} + +void btbb_packet_set_uap(btbb_packet *pkt, uint8_t uap) +{ + pkt->UAP = uap; + btbb_packet_set_flag(pkt, BTBB_UAP_VALID, 1); +} + +uint8_t btbb_packet_get_uap(const btbb_packet *pkt) +{ + return pkt->UAP; +} + +uint16_t btbb_packet_get_nap(const btbb_packet *pkt) +{ + return pkt->NAP; +} + +uint32_t btbb_packet_get_clkn(const btbb_packet *pkt) { + return pkt->clkn; +} + +uint8_t btbb_packet_get_channel(const btbb_packet *pkt) { + return pkt->channel; +} + +void btbb_packet_set_modulation(btbb_packet *pkt, uint8_t modulation) { + pkt->modulation = modulation; +} + +uint8_t btbb_packet_get_modulation(const btbb_packet *pkt) { + return pkt->modulation; +} + +void btbb_packet_set_transport(btbb_packet *pkt, uint8_t transport) { + pkt->transport = transport; +} + +uint8_t btbb_packet_get_transport(const btbb_packet *pkt) { + return pkt->transport; +} + +uint8_t btbb_packet_get_ac_errors(const btbb_packet *pkt) { + return pkt->ac_errors; +} + +int promiscuous_packet_search(char *stream, int search_length, uint32_t *lap, + int max_ac_errors, uint8_t *ac_errors) { + uint64_t syncword, codeword, syndrome, corrected_barker; + syndrome_struct *errors; + char *symbols; + int count, offset = -1; + + /* Barker code at end of sync word (includes + * MSB of LAP) is used as a rough filter. + */ + uint8_t barker = air_to_host8(&stream[57], 6); + barker <<= 1; + + for (count = 0; count < search_length; count++) { + symbols = &stream[count]; + barker >>= 1; + barker |= (symbols[63] << 6); + if (BARKER_DISTANCE[barker] <= MAX_BARKER_ERRORS) { + // Error correction + syncword = air_to_host64(symbols, 64); + + /* correct the barker code with a simple comparison */ + corrected_barker = barker_correct[(uint8_t)(syncword >> 57)]; + syncword = (syncword & 0x01ffffffffffffffULL) | corrected_barker; + + codeword = syncword ^ pn; + + /* Zero syndrome -> good codeword. */ + syndrome = gen_syndrome(codeword); + *ac_errors = 0; + + /* Try to fix errors in bad codeword. */ + if (syndrome) { + errors = find_syndrome(syndrome); + if (errors != NULL) { + syncword ^= errors->error; + *ac_errors = count_bits(errors->error); + syndrome = 0; + } + else { + *ac_errors = 0xff; // fail + } + } + + if (*ac_errors <= max_ac_errors) { + *lap = (syncword >> 34) & 0xffffff; + offset = count; + break; + } + } + } + return offset; +} + +/* Matching a specific LAP */ +int find_known_lap(char *stream, int search_length, uint32_t lap, + int max_ac_errors, uint8_t *ac_errors) { + uint64_t syncword, ac; + char *symbols; + int count, offset = -1; + + ac = btbb_gen_syncword(lap); + for (count = 0; count < search_length; count++) { + symbols = &stream[count]; + syncword = air_to_host64(symbols, 64); + *ac_errors = count_bits(syncword ^ ac); + + if (*ac_errors <= max_ac_errors) { + offset = count; + break; + } + } + return offset; +} + +/* Looks for an AC in the stream */ +int btbb_find_ac(char *stream, int search_length, uint32_t lap, + int max_ac_errors, btbb_packet **pkt_ptr) { + int offset; + uint8_t ac_errors; + + /* Matching any LAP */ + if (lap == LAP_ANY) + offset = promiscuous_packet_search(stream, search_length, &lap, + max_ac_errors, &ac_errors); + else + offset = find_known_lap(stream, search_length, lap, + max_ac_errors, &ac_errors); + + if (offset >= 0) { + if (*pkt_ptr == NULL) + *pkt_ptr = btbb_packet_new(); + init_packet(*pkt_ptr, lap, ac_errors); + } + + return offset; +} + +/* Copy data (symbols) into packet and set rx data. */ +void btbb_packet_set_data(btbb_packet *pkt, char *data, int length, + uint8_t channel, uint32_t clkn) +{ + int i; + + if (length > MAX_SYMBOLS) + length = MAX_SYMBOLS; + for (i = 0; i < length; i++) + pkt->symbols[i] = data[i]; + + pkt->length = length; + pkt->channel = channel; + pkt->clkn = clkn >> 1; // really CLK1 +} + +void btbb_packet_set_flag(btbb_packet *pkt, int flag, int val) +{ + uint32_t mask = 1L << flag; + pkt->flags &= ~mask; + if (val) + pkt->flags |= mask; +} + +int btbb_packet_get_flag(const btbb_packet *pkt, int flag) +{ + uint32_t mask = 1L << flag; + return ((pkt->flags & mask) != 0); +} + +const char *btbb_get_symbols(const btbb_packet* pkt) +{ + return (const char*) pkt->symbols; +} + +int btbb_packet_get_payload_length(const btbb_packet* pkt) +{ + return pkt->payload_length; +} + +const char *btbb_get_payload(const btbb_packet* pkt) +{ + return (const char*) pkt->payload; +} + +int btbb_get_payload_packed(const btbb_packet* pkt, char *dst) +{ + int i; + for(i=0;ipayload_length;i++) + dst[i] = (char) air_to_host8(&pkt->payload[i*8], 8); + return pkt->payload_length; +} + +uint8_t btbb_packet_get_type(const btbb_packet* pkt) +{ + return pkt->packet_type; +} + +uint8_t btbb_packet_get_lt_addr(const btbb_packet* pkt) +{ + return pkt->packet_lt_addr; +} + +uint8_t btbb_packet_get_header_flags(const btbb_packet* pkt) +{ + return pkt->packet_flags; +} + +uint8_t btbb_packet_get_hec(const btbb_packet* pkt) +{ + return pkt->packet_hec; +} + +uint32_t btbb_packet_get_header_packed(const btbb_packet* pkt) +{ + return air_to_host32(&pkt->packet_header[0], 18); +} + +/* Reverse the bits in a byte */ +static uint8_t reverse(char byte) +{ + return (byte & 0x80) >> 7 | (byte & 0x40) >> 5 | (byte & 0x20) >> 3 | (byte & 0x10) >> 1 | (byte & 0x08) << 1 | (byte & 0x04) << 3 | (byte & 0x02) << 5 | (byte & 0x01) << 7; +} + + +/* Decode 1/3 rate FEC, three like symbols in a row */ +static int unfec13(char *input, char *output, int length) +{ + int a, b, c, i; + int be = 0; /* bit errors */ + + for (i = 0; i < length; i++) { + a = 3 * i; + b = a + 1; + c = a + 2; + output[i] = ((input[a] & input[b]) | (input[b] & input[c]) | + (input[c] & input[a])); + be += ((input[a] ^ input[b]) | (input[b] ^ input[c]) | + (input[c] ^ input[a])); + } + + return (be < (length / 4)); +} + +/* encode 10 bits with 2/3 rate FEC code, a (15,10) shortened Hamming code */ +static uint16_t fec23(uint16_t data) +{ + int i; + uint16_t codeword = 0; + + /* host order, not air order */ + for (i = 0; i < 10; i++) + if (data & (1 << i)) + codeword ^= fec23_gen_matrix[i]; + + return codeword; +} + +/* Decode 2/3 rate FEC, a (15,10) shortened Hamming code */ +static char *unfec23(char *input, int length) +{ + /* input points to the input data + * length is length in bits of the data + * before it was encoded with fec2/3 */ + int iptr, optr, count; + char* output; + uint8_t diff, check; + uint16_t data, codeword; + + diff = length % 10; + // padding at end of data + if(0!=diff) + length += (10 - diff); + + output = (char *) malloc(length); + + for (iptr = 0, optr = 0; optr> 10); + + /* no errors or single bit errors (errors in the parity bit): + * (a strong hint it's a real packet) + * Otherwise we need to corret the output*/ + if (diff & (diff - 1)) { + switch (diff) { + /* comments are the bit that's wrong and the value + * of diff in air order, from the BT spec */ + // 1000000000 11010 + case 0x0b: output[optr] ^= 1; break; + // 0100000000 01101 + case 0x16: output[optr+1] ^= 1; break; + // 0010000000 11100 + case 0x07: output[optr+2] ^= 1; break; + // 0001000000 01110 + case 0x0e: output[optr+3] ^= 1; break; + // 0000100000 00111 + case 0x1c: output[optr+4] ^= 1; break; + // 0000010000 11001 + case 0x13: output[optr+5] ^= 1; break; + // 0000001000 10110 + case 0x0d: output[optr+6] ^= 1; break; + // 0000000100 01011 + case 0x1a: output[optr+7] ^= 1; break; + // 0000000010 11111 + case 0x1f: output[optr+8] ^= 1; break; + // 0000000001 10101 + case 0x15: output[optr+9] ^= 1; break; + /* not one of these errors, probably multiple bit errors + * or maybe not a real packet, safe to drop it? */ + default: free(output); return 0; + } + } + } + return output; +} + + +/* Remove the whitening from an air order array */ +static void unwhiten(char* input, char* output, int clock, int length, int skip, btbb_packet* pkt) +{ + int count, index; + index = INDICES[clock & 0x3f]; + index += skip; + index %= 127; + + for(count = 0; count < length; count++) + { + /* unwhiten if whitened, otherwise just copy input to output */ + output[count] = btbb_packet_get_flag(pkt, BTBB_WHITENED) ? + input[count] ^ WHITENING_DATA[index] : input[count]; + index += 1; + index %= 127; + } +} + +/* Pointer to start of packet, length of packet in bits, UAP */ +static uint16_t crcgen(char *payload, int length, int UAP) +{ + char bit; + uint16_t reg, count; + + reg = (reverse(UAP) << 8) & 0xff00; + for(count = 0; count < length; count++) + { + bit = payload[count]; + + reg = (reg >> 1) | (((reg & 0x0001) ^ (bit & 0x01))<<15); + + /*Bit 5*/ + reg ^= ((reg & 0x8000)>>5); + + /*Bit 12*/ + reg ^= ((reg & 0x8000)>>12); + } + return reg; +} + +/* extract UAP by reversing the HEC computation */ +static uint8_t uap_from_hec(uint16_t data, uint8_t hec) +{ + int i; + + for (i = 9; i >= 0; i--) { + /* 0x65 is xor'd if MSB is 1, else 0x00 (which does nothing) */ + if (hec & 0x80) + hec ^= 0x65; + + hec = (hec << 1) | (((hec >> 7) ^ (data >> i)) & 0x01); + } + return reverse(hec); +} + +/* check if the packet's CRC is correct for a given clock (CLK1-6) */ +int crc_check(int clock, btbb_packet* pkt) +{ + /* + * return value of 1 represents inconclusive result (default) + * return value > 1 represents positive result (e.g. CRC match) + * return value of 0 represents negative result (e.g. CRC failure without + * the possibility that we have assumed the wrong logical transport) + */ + int retval = 1; + + switch(pkt->packet_type) + { + case PACKET_TYPE_FHS: + retval = fhs(clock, pkt); + break; + + case PACKET_TYPE_DV: + case PACKET_TYPE_DM1: + case PACKET_TYPE_DM3: + case PACKET_TYPE_DM5: + retval = DM(clock, pkt); + break; + + case PACKET_TYPE_DH1: + case PACKET_TYPE_DH3: + case PACKET_TYPE_DH5: + retval = DH(clock, pkt); + break; + + case PACKET_TYPE_HV3: /* EV3 */ + retval = EV3(clock, pkt); + break; + case PACKET_TYPE_EV4: + retval = EV4(clock, pkt); + break; + case PACKET_TYPE_EV5: + retval = EV5(clock, pkt); + break; + + case PACKET_TYPE_HV1: + retval = HV(clock, pkt); + break; + + /* some types can't help us */ + default: + break; + } + /* + * never return a zero result unless this is a FHS, DM1, or HV1. any + * other type could have actually been something else (another logical + * transport) + */ + if (retval == 0 && (pkt->packet_type != 2 && pkt->packet_type != 3 && + pkt->packet_type != 5)) + return 1; + + /* EV3 and EV5 have a relatively high false positive rate */ + if (retval > 1 && (pkt->packet_type == 7 || pkt->packet_type == 13)) + return 1; + + return retval; +} + +/* verify the payload CRC */ +static int payload_crc(btbb_packet* pkt) +{ + uint16_t crc; /* CRC calculated from payload data */ + uint16_t check; /* CRC supplied by packet */ + + crc = crcgen(pkt->payload, (pkt->payload_length - 2) * 8, pkt->UAP); + check = air_to_host16(&pkt->payload[(pkt->payload_length - 2) * 8], 16); + + return (crc == check); +} + +int fhs(int clock, btbb_packet* pkt) +{ + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + pkt->payload_length = 20; + + if (size < pkt->payload_length * 12) + return 1; //FIXME should throw exception + + char *corrected = unfec23(stream, pkt->payload_length * 8); + if (!corrected) + return 0; + + /* try to unwhiten with known clock bits */ + unwhiten(corrected, pkt->payload, clock, pkt->payload_length * 8, 18, pkt); + if (payload_crc(pkt)) { + free(corrected); + return 1000; + } + + /* try all 32 possible X-input values instead */ + for (clock = 32; clock < 64; clock++) { + unwhiten(corrected, pkt->payload, clock, pkt->payload_length * 8, 18, pkt); + if (payload_crc(pkt)) { + free(corrected); + return 1000; + } + } + + /* failed to unwhiten */ + free(corrected); + return 0; +} + +/* decode payload header, return value indicates success */ +static int decode_payload_header(char *stream, int clock, int header_bytes, int size, int fec, btbb_packet* pkt) +{ + if(header_bytes == 2) + { + if(size < 16) + return 0; //FIXME should throw exception + if(fec) { + if(size < 30) + return 0; //FIXME should throw exception + char *corrected = unfec23(stream, 16); + if (!corrected) + return 0; + unwhiten(corrected, pkt->payload_header, clock, 16, 18, pkt); + free(corrected); + } else { + unwhiten(stream, pkt->payload_header, clock, 16, 18, pkt); + } + /* payload length is payload body length + 2 bytes payload header + 2 bytes CRC */ + pkt->payload_length = air_to_host16(&pkt->payload_header[3], 10) + 4; + } else { + if(size < 8) + return 0; //FIXME should throw exception + if(fec) { + if(size < 15) + return 0; //FIXME should throw exception + char *corrected = unfec23(stream, 8); + if (!corrected) + return 0; + unwhiten(corrected, pkt->payload_header, clock, 8, 18, pkt); + free(corrected); + } else { + unwhiten(stream, pkt->payload_header, clock, 8, 18, pkt); + } + /* payload length is payload body length + 1 byte payload header + 2 bytes CRC */ + pkt->payload_length = air_to_host8(&pkt->payload_header[3], 5) + 3; + } + /* Try to set the max payload length to a sensible value, + * especially when using strange data + */ + int max_length = 0; + switch(pkt->packet_type) { + case PACKET_TYPE_DM1: + max_length = 20; + break; + case PACKET_TYPE_DH1: + /* assuming DH1 but could be 2-DH1 (58) */ + max_length = 30; + break; + case PACKET_TYPE_DV: + /* assuming DV but could be 3-DH1 (87) */ + max_length = 12; /* + 10bytes of voice data */ + break; + case PACKET_TYPE_DM3: + /* assuming DM3 but could be 2-DH3 (371) */ + max_length = 125; + break; + case PACKET_TYPE_DH3: + /* assuming DH3 but could be 3-DH3 (556) */ + max_length = 187; + break; + case PACKET_TYPE_DM5: + /* assuming DM5 but could be 2-DH5 (683) */ + max_length = 228; + break; + case PACKET_TYPE_DH5: + /* assuming DH5 but could be 3-DH5 (1025) */ + max_length = 343; + break; + } + pkt->payload_length = MIN(pkt->payload_length, max_length); + pkt->payload_llid = air_to_host8(&pkt->payload_header[0], 2); + pkt->payload_flow = air_to_host8(&pkt->payload_header[2], 1); + pkt->payload_header_length = header_bytes; + return 1; +} + +/* DM 1/3/5 packet (and DV)*/ +int DM(int clock, btbb_packet* pkt) +{ + int bitlength; + /* number of bytes in the payload header */ + int header_bytes = 2; + /* maximum payload length */ + int max_length; + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + switch(pkt->packet_type) + { + case PACKET_TYPE_DV: + /* skip 80 voice bits, then treat the rest like a DM1 */ + stream += 80; + size -= 80; + header_bytes = 1; + /* I don't think the length of the voice field ("synchronous data + * field") is included in the length indicated by the payload + * header in the data field ("asynchronous data field"), but I + * could be wrong. + */ + max_length = 12; + break; + case PACKET_TYPE_DM1: + header_bytes = 1; + max_length = 20; + break; + case PACKET_TYPE_DM3: + max_length = 125; + break; + case PACKET_TYPE_DM5: + max_length = 228; + break; + default: /* not a DM1/3/5 or DV */ + return 0; + } + if(!decode_payload_header(stream, clock, header_bytes, size, 1, pkt)) + return 0; + /* check that the length indicated in the payload header is within spec */ + if(pkt->payload_length > max_length) + /* could be encrypted */ + return 1; + bitlength = pkt->payload_length*8; + if(bitlength > size) + return 1; //FIXME should throw exception + + char *corrected = unfec23(stream, bitlength); + if (!corrected) + return 0; + unwhiten(corrected, pkt->payload, clock, bitlength, 18, pkt); + free(corrected); + + if (payload_crc(pkt)) + return 10; + + /* could be encrypted */ + return 2; +} + +/* DH 1/3/5 packet (and AUX1) */ +/* similar to DM 1/3/5 but without FEC */ +int DH(int clock, btbb_packet* pkt) +{ + int bitlength; + /* number of bytes in the payload header */ + int header_bytes = 2; + /* maximum payload length */ + int max_length; + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + switch(pkt->packet_type) + { + case PACKET_TYPE_AUX1: + case PACKET_TYPE_DH1: + header_bytes = 1; + max_length = 30; + break; + case PACKET_TYPE_DH3: + max_length = 187; + break; + case PACKET_TYPE_DH5: + max_length = 343; + break; + default: /* not a DH1/3/5 */ + return 0; + } + if(!decode_payload_header(stream, clock, header_bytes, size, 0, pkt)) + return 0; + /* check that the length indicated in the payload header is within spec */ + if(pkt->payload_length > max_length) + /* could be encrypted */ + return 1; + bitlength = pkt->payload_length*8; + if(bitlength > size) + return 1; //FIXME should throw exception + + unwhiten(stream, pkt->payload, clock, bitlength, 18, pkt); + + /* AUX1 has no CRC */ + if (pkt->packet_type == 9) + return 2; + + if (payload_crc(pkt)) + return 10; + + /* could be encrypted */ + return 2; +} + +int EV3(int clock, btbb_packet* pkt) +{ + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + /* maximum payload length is 30 bytes + 2 bytes CRC */ + int maxlength = 32; + + /* number of bits we have decoded */ + int bits; + + /* check CRC for any integer byte length up to maxlength */ + for (pkt->payload_length = 0; + pkt->payload_length < maxlength; pkt->payload_length++) { + + bits = pkt->payload_length * 8; + + /* unwhiten next byte */ + if ((bits + 8) > size) + return 1; //FIXME should throw exception + unwhiten(stream, pkt->payload + bits, clock, 8, 18 + bits, pkt); + + if ((pkt->payload_length > 2) && (payload_crc(pkt))) + return 10; + } + return 2; +} + +int EV4(int clock, btbb_packet* pkt) +{ + char *corrected; + + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + /* + * maximum payload length is 120 bytes + 2 bytes CRC + * after FEC2/3, this results in a maximum of 1470 symbols + */ + int maxlength = 1470; + + /* + * minumum payload length is 1 bytes + 2 bytes CRC + * after FEC2/3, this results in a minimum of 45 symbols + */ + int minlength = 45; + + int syms = 0; /* number of symbols we have decoded */ + int bits = 0; /* number of payload bits we have decoded */ + + pkt->payload_length = 1; + + while (syms < maxlength) { + + /* unfec/unwhiten next block (15 symbols -> 10 bits) */ + if (syms + 15 > size) + return 1; //FIXME should throw exception + corrected = unfec23(stream + syms, 10); + if (!corrected) { + free(corrected); + if (syms < minlength) + return 0; + else + return 1; + } + unwhiten(corrected, pkt->payload + bits, clock, 10, 18 + bits, pkt); + free(corrected); + + /* check CRC one byte at a time */ + while (pkt->payload_length * 8 <= bits) { + if (payload_crc(pkt)) + return 10; + pkt->payload_length++; + } + syms += 15; + bits += 10; + } + return 2; +} + +int EV5(int clock, btbb_packet* pkt) +{ + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + /* maximum payload length is 180 bytes + 2 bytes CRC */ + int maxlength = 182; + + /* number of bits we have decoded */ + int bits; + + /* check CRC for any integer byte length up to maxlength */ + for (pkt->payload_length = 0; + pkt->payload_length < maxlength; pkt->payload_length++) { + + bits = pkt->payload_length * 8; + + /* unwhiten next byte */ + if ((bits + 8) > size) + return 1; //FIXME should throw exception + unwhiten(stream, pkt->payload + bits, clock, 8, 18 + bits, pkt); + + if ((pkt->payload_length > 2) && (payload_crc(pkt))) + return 10; + } + return 2; +} + +/* HV packet type payload parser */ +int HV(int clock, btbb_packet* pkt) +{ + /* skip the access code and packet header */ + char *stream = pkt->symbols + 122; + /* number of symbols remaining after access code and packet header */ + int size = pkt->length - 122; + + pkt->payload_header_length = 0; + if(size < 240) { + pkt->payload_length = 0; + return 1; //FIXME should throw exception + } + + switch (pkt->packet_type) { + case PACKET_TYPE_HV1: + { + char corrected[80]; + if (!unfec13(stream, corrected, 80)) + return 0; + pkt->payload_length = 10; + btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1); + unwhiten(corrected, pkt->payload, clock, pkt->payload_length*8, 18, pkt); + } + break; + case PACKET_TYPE_HV2: + { + char *corrected = unfec23(stream, 160); + if (!corrected) + return 0; + pkt->payload_length = 20; + btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1); + unwhiten(corrected, pkt->payload, clock, pkt->payload_length*8, 18, pkt); + free(corrected); + } + break; + case PACKET_TYPE_HV3: + pkt->payload_length = 30; + btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1); + unwhiten(stream, pkt->payload, clock, pkt->payload_length*8, 18, pkt); + break; + } + + return 2; +} +/* try a clock value (CLK1-6) to unwhiten packet header, + * sets resultant p->packet_type and p->UAP, returns UAP. + */ +uint8_t try_clock(int clock, btbb_packet* pkt) +{ + /* skip 72 bit access code */ + char *stream = pkt->symbols + 68; + /* 18 bit packet header */ + char header[18]; + char unwhitened[18]; + + if (!unfec13(stream, header, 18)) + return 0; + unwhiten(header, unwhitened, clock, 18, 0, pkt); + uint16_t hdr_data = air_to_host16(unwhitened, 10); + uint8_t hec = air_to_host8(&unwhitened[10], 8); + pkt->UAP = uap_from_hec(hdr_data, hec); + pkt->packet_type = air_to_host8(&unwhitened[3], 4); + + return pkt->UAP; +} + +/* decode the packet header */ +int btbb_decode_header(btbb_packet* pkt) +{ + /* skip 72 bit access code */ + char *stream = pkt->symbols + 68; + /* 18 bit packet header */ + char header[18]; + uint8_t UAP; + + if (btbb_packet_get_flag(pkt, BTBB_CLK6_VALID) && unfec13(stream, header, 18)) { + unwhiten(header, pkt->packet_header, pkt->clock, 18, 0, pkt); + uint16_t hdr_data = air_to_host16(pkt->packet_header, 10); + uint8_t hec = air_to_host8(&pkt->packet_header[10], 8); + UAP = uap_from_hec(hdr_data, hec); + if (UAP == pkt->UAP) { + pkt->packet_lt_addr = air_to_host8(&pkt->packet_header[0], 3); + pkt->packet_type = air_to_host8(&pkt->packet_header[3], 4); + pkt->packet_flags = air_to_host8(&pkt->packet_header[7], 3); + pkt->packet_hec = hec; + return 1; + } + } + + return 0; +} + +int btbb_decode_payload(btbb_packet* pkt) +{ + int rv = 0; + pkt->payload_header_length = 0; + + switch(pkt->packet_type) + { + case PACKET_TYPE_NULL: + /* no payload to decode */ + pkt->payload_length = 0; + rv = 1; + break; + case PACKET_TYPE_POLL: + /* no payload to decode */ + pkt->payload_length = 0; + rv = 1; + break; + case PACKET_TYPE_FHS: + rv = fhs(pkt->clock, pkt); + break; + case PACKET_TYPE_DM1: + rv = DM(pkt->clock, pkt); + break; + case PACKET_TYPE_DH1: + /* assuming DH1 but could be 2-DH1 */ + rv = DH(pkt->clock, pkt); + break; + case PACKET_TYPE_HV1: + rv = HV(pkt->clock, pkt); + break; + case PACKET_TYPE_HV2: + rv = HV(pkt->clock, pkt); + break; + case PACKET_TYPE_HV3: /* HV3/EV3/3-EV3 */ + /* decode as EV3 if CRC checks out */ + if ((rv = EV3(pkt->clock, pkt)) <= 1) + /* otherwise assume HV3 */ + rv = HV(pkt->clock, pkt); + /* don't know how to decode 3-EV3 */ + break; + case PACKET_TYPE_DV: + /* assuming DV but could be 3-DH1 */ + rv = DM(pkt->clock, pkt); + break; + case PACKET_TYPE_AUX1: + rv = DH(pkt->clock, pkt); + break; + case PACKET_TYPE_DM3: + /* assuming DM3 but could be 2-DH3 */ + rv = DM(pkt->clock, pkt); + break; + case PACKET_TYPE_DH3: + /* assuming DH3 but could be 3-DH3 */ + rv = DH(pkt->clock, pkt); + break; + case PACKET_TYPE_EV4: + /* assuming EV4 but could be 2-EV5 */ + rv = EV4(pkt->clock, pkt); + break; + case PACKET_TYPE_EV5: + /* assuming EV5 but could be 3-EV5 */ + rv = EV5(pkt->clock, pkt); + break; + case PACKET_TYPE_DM5: + /* assuming DM5 but could be 2-DH5 */ + rv = DM(pkt->clock, pkt); + break; + case PACKET_TYPE_DH5: + /* assuming DH5 but could be 3-DH5 */ + rv = DH(pkt->clock, pkt); + break; + } + btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 1); + return rv; +} + +/* print packet information */ +void btbb_print_packet(const btbb_packet* pkt) +{ + if (btbb_packet_get_flag(pkt, BTBB_HAS_PAYLOAD)) { + printf(" Type: %s\n", TYPE_NAMES[pkt->packet_type]); + if (pkt->payload_header_length > 0) { + printf(" LT_ADDR: %d\n", pkt->packet_lt_addr); + printf(" LLID: %d\n", pkt->payload_llid); + printf(" flow: %d\n", pkt->payload_flow); + printf(" payload length: %d\n", pkt->payload_length); + } + if (pkt->payload_length) { + printf(" Data: "); + int i; + for(i=0; ipayload_length; i++) + printf(" %02x", air_to_host8(pkt->payload + 8*i, 8)); + printf("\n"); + } + } +} + +char *tun_format(btbb_packet* pkt) +{ + /* include 6 bytes for meta data, 3 bytes for packet header */ + int length = 9 + pkt->payload_length; + char *tun_format = (char *) malloc(length); + int i; + + /* meta data */ + tun_format[0] = pkt->clock & 0xff; + tun_format[1] = (pkt->clock >> 8) & 0xff; + tun_format[2] = (pkt->clock >> 16) & 0xff; + tun_format[3] = (pkt->clock >> 24) & 0xff; + tun_format[4] = pkt->channel; + tun_format[5] = btbb_packet_get_flag(pkt, BTBB_CLK27_VALID) | + (btbb_packet_get_flag(pkt, BTBB_NAP_VALID) << 1); + + /* packet header modified to fit byte boundaries */ + /* lt_addr and type */ + tun_format[6] = (char) air_to_host8(&pkt->packet_header[0], 7); + /* flags */ + tun_format[7] = (char) air_to_host8(&pkt->packet_header[7], 3); + /* HEC */ + tun_format[8] = (char) air_to_host8(&pkt->packet_header[10], 8); + + for(i=0;ipayload_length;i++) + tun_format[i+9] = (char) air_to_host8(&pkt->payload[i*8], 8); + + return tun_format; +} + +/* check to see if the packet has a header */ +int btbb_header_present(const btbb_packet* pkt) +{ + /* skip to last bit of sync word */ + const char *stream = pkt->symbols + 63; + int be = 0; /* bit errors */ + char msb; /* most significant (last) bit of sync word */ + int a, b, c; + + /* check that we have enough symbols */ + if (pkt->length < 122) + return 0; + + /* check that the AC trailer is correct */ + msb = stream[0]; + be += stream[1] ^ !msb; + be += stream[2] ^ msb; + be += stream[3] ^ !msb; + be += stream[4] ^ msb; + + /* + * Each bit of the 18 bit header is repeated three times. Without + * checking the correctness of any particular bit, just count the + * number of times three symbols in a row don't all agree. + */ + stream += 5; + for (a = 0; a < 54; a += 3) { + b = a + 1; + c = a + 2; + be += ((stream[a] ^ stream[b]) | + (stream[b] ^ stream[c]) | (stream[c] ^ stream[a])); + } + + /* + * Few bit errors indicates presence of a header. Many bit errors + * indicates no header is present (i.e. it is an ID packet). + */ + return (be < ID_THRESHOLD); +} + +/* extract LAP from FHS payload */ +uint32_t lap_from_fhs(btbb_packet* pkt) +{ + /* caller should check got_payload() and get_type() */ + return air_to_host32(&pkt->payload[34], 24); +} + +/* extract UAP from FHS payload */ +uint8_t uap_from_fhs(btbb_packet* pkt) +{ + /* caller should check got_payload() and get_type() */ + return air_to_host8(&pkt->payload[64], 8); +} + +/* extract NAP from FHS payload */ +uint16_t nap_from_fhs(btbb_packet* pkt) +{ + /* caller should check got_payload() and get_type() */ + return air_to_host8(&pkt->payload[72], 16); +} + +/* extract clock from FHS payload */ +uint32_t clock_from_fhs(btbb_packet* pkt) +{ + /* + * caller should check got_payload() and get_type() + * + * This is CLK2-27 (units of 1.25 ms). + * CLK0 and CLK1 are implicitly zero. + */ + return air_to_host32(&pkt->payload[115], 26); +} diff --git a/libbtbb-2015-10-R1/lib/src/bluetooth_packet.h b/libbtbb-2015-10-R1/lib/src/bluetooth_packet.h new file mode 100644 index 0000000..27b2a61 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/bluetooth_packet.h @@ -0,0 +1,147 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_BLUETOOTH_PACKET_H +#define INCLUDED_BLUETOOTH_PACKET_H +#include "btbb.h" + +/* maximum number of symbols */ +#define MAX_SYMBOLS 3125 + +/* maximum number of payload bits */ +#define MAX_PAYLOAD_LENGTH 2744 + +/* minimum header bit errors to indicate that this is an ID packet */ +#define ID_THRESHOLD 5 + +#define PACKET_TYPE_NULL 0 +#define PACKET_TYPE_POLL 1 +#define PACKET_TYPE_FHS 2 +#define PACKET_TYPE_DM1 3 +#define PACKET_TYPE_DH1 4 +#define PACKET_TYPE_HV1 5 +#define PACKET_TYPE_HV2 6 +#define PACKET_TYPE_HV3 7 +#define PACKET_TYPE_DV 8 +#define PACKET_TYPE_AUX1 9 +#define PACKET_TYPE_DM3 10 +#define PACKET_TYPE_DH3 11 +#define PACKET_TYPE_EV4 12 +#define PACKET_TYPE_EV5 13 +#define PACKET_TYPE_DM5 14 +#define PACKET_TYPE_DH5 15 + +struct btbb_packet { + + uint32_t refcount; + + uint32_t flags; + + uint8_t channel; /* Bluetooth channel (0-79) */ + uint8_t UAP; /* upper address part */ + uint16_t NAP; /* non-significant address part */ + uint32_t LAP; /* lower address part found in access code */ + + uint8_t modulation; + uint8_t transport; + uint8_t packet_type; + uint8_t packet_lt_addr; /* LLID field of payload header (2 bits) */ + uint8_t packet_flags; /* Flags - FLOW/ARQN/SQEN */ + uint8_t packet_hec; /* Flags - FLOW/ARQN/SQEN */ + + /* packet header, one bit per char */ + char packet_header[18]; + + /* number of payload header bytes: 0, 1, 2, or -1 for + * unknown. payload is one bit per char. */ + int payload_header_length; + char payload_header[16]; + + /* LLID field of payload header (2 bits) */ + uint8_t payload_llid; + + /* flow field of payload header (1 bit) */ + uint8_t payload_flow; + + /* payload length: the total length of the asynchronous data + * in bytes. This does not include the length of synchronous + * data, such as the voice field of a DV packet. If there is a + * payload header, this payload length is payload body length + * (the length indicated in the payload header's length field) + * plus payload_header_length plus 2 bytes CRC (if present). + */ + int payload_length; + + /* The actual payload data in host format + * Ready for passing to wireshark + * 2744 is the maximum length, but most packets are shorter. + * Dynamic allocation would probably be better in the long run but is + * problematic in the short run. + */ + char payload[MAX_PAYLOAD_LENGTH]; + + uint16_t crc; + uint32_t clock; /* CLK1-27 of master */ + uint32_t clkn; /* native (local) clock, CLK0-27 */ + uint8_t ac_errors; /* Number of bit errors in the AC */ + + /* the raw symbol stream (less the preamble), one bit per char */ + //FIXME maybe this should be a vector so we can grow it only + //to the size needed and later shrink it if we find we have + //more symbols than necessary + uint16_t length; /* number of symbols */ + char symbols[MAX_SYMBOLS]; + +}; + +/* type-specific CRC checks and decoding */ +int fhs(int clock, btbb_packet* p); +int DM(int clock, btbb_packet* p); +int DH(int clock, btbb_packet* p); +int EV3(int clock, btbb_packet* p); +int EV4(int clock, btbb_packet* p); +int EV5(int clock, btbb_packet* p); +int HV(int clock, btbb_packet* p); + +/* check if the packet's CRC is correct for a given clock (CLK1-6) */ +int crc_check(int clock, btbb_packet* p); + +/* format payload for tun interface */ +char *tun_format(btbb_packet* p); + +/* try a clock value (CLK1-6) to unwhiten packet header, + * sets resultant d_packet_type and d_UAP, returns UAP. + */ +uint8_t try_clock(int clock, btbb_packet* p); + +/* extract LAP from FHS payload */ +uint32_t lap_from_fhs(btbb_packet* p); + +/* extract UAP from FHS payload */ +uint8_t uap_from_fhs(btbb_packet* p); + +/* extract NAP from FHS payload */ +uint16_t nap_from_fhs(btbb_packet* p); + +/* extract clock from FHS payload */ +uint32_t clock_from_fhs(btbb_packet* p); + +#endif /* INCLUDED_BLUETOOTH_PACKET_H */ diff --git a/libbtbb-2015-10-R1/lib/src/bluetooth_piconet.c b/libbtbb-2015-10-R1/lib/src/bluetooth_piconet.c new file mode 100644 index 0000000..751a34d --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/bluetooth_piconet.c @@ -0,0 +1,953 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "bluetooth_packet.h" +#include "bluetooth_piconet.h" +#include "uthash.h" +#include +#include + +int perm_table_initialized = 0; +char perm_table[0x20][0x20][0x200]; + +/* count the number of 1 bits in a uint64_t */ +int count_bits(uint8_t n) +{ + int i = 0; + for (i = 0; n != 0; i++) + n &= n - 1; + return i; +} + +btbb_piconet * +btbb_piconet_new(void) +{ + btbb_piconet *pn = (btbb_piconet *)calloc(1, sizeof(btbb_piconet)); + pn->refcount = 1; + return pn; +} + +void +btbb_piconet_ref(btbb_piconet *pn) +{ + pn->refcount++; +} + +void +btbb_piconet_unref(btbb_piconet *pn) +{ + pn->refcount--; + if (pn->refcount == 0) + free(pn); +} + +/* A bit of a hack? to set survey mode */ +static int survey_mode = 0; +int btbb_init_survey() { + survey_mode = 1; + return 0; +} + +void btbb_init_piconet(btbb_piconet *pn, uint32_t lap) +{ + pn->LAP = lap; + btbb_piconet_set_flag(pn, BTBB_LAP_VALID, 1); +} + +void btbb_piconet_set_flag(btbb_piconet *pn, int flag, int val) +{ + uint32_t mask = 1L << flag; + pn->flags &= ~mask; + if (val) + pn->flags |= mask; +} + +int btbb_piconet_get_flag(const btbb_piconet *pn, const int flag) +{ + uint32_t mask = 1L << flag; + return ((pn->flags & mask) != 0); +} + +void btbb_piconet_set_uap(btbb_piconet *pn, uint8_t uap) +{ + pn->UAP = uap; + btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); +} + +uint8_t btbb_piconet_get_uap(const btbb_piconet *pn) +{ + return pn->UAP; +} + +uint32_t btbb_piconet_get_lap(const btbb_piconet *pn) +{ + return pn->LAP; +} + +uint16_t btbb_piconet_get_nap(const btbb_piconet *pn) +{ + return pn->NAP; +} + +uint64_t btbb_piconet_get_bdaddr(const btbb_piconet *pn) +{ + return ((uint64_t) pn->NAP) << 32 | pn->UAP << 24 | pn->LAP; +} + +int btbb_piconet_get_clk_offset(const btbb_piconet *pn) +{ + return pn->clk_offset; +} + +void btbb_piconet_set_clk_offset(btbb_piconet *pn, int clk_offset) +{ + pn->clk_offset = clk_offset; +} + +void btbb_piconet_set_afh_map(btbb_piconet *pn, uint8_t *afh_map) { + int i; + pn->used_channels = 0; + // DGS: Unroll this? + for(i=0; i<10; i++) { + pn->afh_map[i] = afh_map[i]; + pn->used_channels += count_bits(pn->afh_map[i]); + } + if(btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) + get_hop_pattern(pn); +} + +uint8_t *btbb_piconet_get_afh_map(btbb_piconet *pn) { + return pn->afh_map; +} + +void btbb_piconet_set_channel_seen(btbb_piconet *pn, uint8_t channel) +{ + if(!(pn->afh_map[channel/8] & 0x1 << (channel % 8))) { + pn->afh_map[channel/8] |= 0x1 << (channel % 8); + pn->used_channels++; + if(btbb_piconet_get_flag(pn, BTBB_UAP_VALID) && !survey_mode) + get_hop_pattern(pn); + } +} + +uint8_t btbb_piconet_get_channel_seen(btbb_piconet *pn, uint8_t channel) +{ + if(channel < BT_NUM_CHANNELS) + return ( pn->afh_map[channel/8] & (1 << (channel % 8)) ) != 0; + else + return 1; +} + +/* do all the precalculation that can be done before knowing the address */ +void precalc(btbb_piconet *pn) +{ + int i = 0; + int j = 0; + int chan; + + /* populate frequency register bank*/ + for (i = 0; i < BT_NUM_CHANNELS; i++) { + + /* AFH is used, hopping sequence contains only used channels */ + if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) { + chan = (i * 2) % BT_NUM_CHANNELS; + if(btbb_piconet_get_channel_seen(pn, chan)) + pn->bank[j++] = chan; + } + + /* all channels are used */ + else { + pn->bank[i] = ((i * 2) % BT_NUM_CHANNELS); + } + } + /* actual frequency is 2402 + pn->bank[i] MHz */ + +} + +/* do precalculation that requires the address */ +void address_precalc(int address, btbb_piconet *pn) +{ + /* precalculate some of single_hop()/gen_hop()'s variables */ + pn->a1 = (address >> 23) & 0x1f; + pn->b = (address >> 19) & 0x0f; + pn->c1 = ((address >> 4) & 0x10) + + ((address >> 3) & 0x08) + + ((address >> 2) & 0x04) + + ((address >> 1) & 0x02) + + (address & 0x01); + pn->d1 = (address >> 10) & 0x1ff; + pn->e = ((address >> 7) & 0x40) + + ((address >> 6) & 0x20) + + ((address >> 5) & 0x10) + + ((address >> 4) & 0x08) + + ((address >> 3) & 0x04) + + ((address >> 2) & 0x02) + + ((address >> 1) & 0x01); +} + +#ifdef WC4 +/* These are optimization experiments, which don't help much for + * x86. Hold on to them to see whether they're useful on ARM. */ + +#ifdef NEVER +#define BUTTERFLY(z,p,c,a,b) \ + if ( ((p&(1<>a)^(z>>b)) & (p>>c)) & 0x1 ) \ + z ^= ((1<> i) & 0x01; + for (i = 0; i < 5; i++) + p[i+9] = (p_high >> i) & 0x01; + + /* bit swapping will be easier with an array of bits */ + for (i = 0; i < 5; i++) + z_bit[i] = (z >> i) & 0x01; + + /* butterfly operations */ + for (i = 13; i >= 0; i--) { + /* swap bits according to index arrays if control signal tells us to */ + if (p[i]) { + tmp = z_bit[index1[i]]; + z_bit[index1[i]] = z_bit[index2[i]]; + z_bit[index2[i]] = tmp; + } + } + + /* reconstruct output from rearranged bits */ + output = 0; + for (i = 0; i < 5; i++) + output += z_bit[i] << i; + + return(output); +} + +void perm_table_init(void) +{ + /* populate perm_table for all possible inputs */ + int z, p_high, p_low; + for (z = 0; z < 0x20; z++) + for (p_high = 0; p_high < 0x20; p_high++) + for (p_low = 0; p_low < 0x200; p_low++) + perm_table[z][p_high][p_low] = perm5(z, p_high, p_low); +} + +/* drop-in replacement for perm5() using lookup table */ +int fast_perm(int z, int p_high, int p_low) +{ + if (!perm_table_initialized) { + perm_table_init(); + perm_table_initialized = 1; + } + + return(perm_table[z][p_high][p_low]); +} + +/* generate the complete hopping sequence */ +static void gen_hops(btbb_piconet *pn) +{ + /* a, b, c, d, e, f, x, y1, y2 are variable names used in section 2.6 of the spec */ + /* b is already defined */ + /* e is already defined */ + int a, c, d, x; + uint32_t base_f, f, f_dash; + int h, i, j, k, c_flipped, perm_in, perm_out; + + /* sequence index = clock >> 1 */ + /* (hops only happen at every other clock value) */ + int index = 0; + base_f = 0; + f = 0; + f_dash = 0; + + /* nested loops for optimization (not recalculating every variable with every clock tick) */ + for (h = 0; h < 0x04; h++) { /* clock bits 26-27 */ + for (i = 0; i < 0x20; i++) { /* clock bits 21-25 */ + a = pn->a1 ^ i; + for (j = 0; j < 0x20; j++) { /* clock bits 16-20 */ + c = pn->c1 ^ j; + c_flipped = c ^ 0x1f; + for (k = 0; k < 0x200; k++) { /* clock bits 7-15 */ + d = pn->d1 ^ k; + for (x = 0; x < 0x20; x++) { /* clock bits 2-6 */ + perm_in = ((x + a) % 32) ^ pn->b; + + /* y1 (clock bit 1) = 0, y2 = 0 */ + perm_out = fast_perm(perm_in, c, d); + if (btbb_piconet_get_flag(pn, BTBB_IS_AFH)) + pn->sequence[index] = pn->bank[(perm_out + pn->e + f_dash) % pn->used_channels]; + else + pn->sequence[index] = pn->bank[(perm_out + pn->e + f) % BT_NUM_CHANNELS]; + + /* y1 (clock bit 1) = 1, y2 = 32 */ + perm_out = fast_perm(perm_in, c_flipped, d); + if (btbb_piconet_get_flag(pn, BTBB_IS_AFH)) + pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f_dash + 32) % pn->used_channels]; + else + pn->sequence[index + 1] = pn->bank[(perm_out + pn->e + f + 32) % BT_NUM_CHANNELS]; + + index += 2; + } + base_f += 16; + f = base_f % BT_NUM_CHANNELS; + f_dash = f % pn->used_channels; + } + } + } + } +} + +/* Function to calculate piconet hopping patterns and add to hash map */ +void gen_hop_pattern(btbb_piconet *pn) +{ + printf("\nCalculating complete hopping sequence.\n"); + /* this holds the entire hopping sequence */ + pn->sequence = (char*) malloc(SEQUENCE_LENGTH); + + precalc(pn); + address_precalc(((pn->UAP<<24) | pn->LAP) & 0xfffffff, pn); + gen_hops(pn); + + printf("Hopping sequence calculated.\n"); +} + +/* Container for hopping pattern */ +typedef struct { + uint64_t key; /* afh flag + address */ + char *sequence; + UT_hash_handle hh; +} hopping_struct; + +static hopping_struct *hopping_map = NULL; + +/* Function to fetch piconet hopping patterns */ +void get_hop_pattern(btbb_piconet *pn) +{ + hopping_struct *s; + uint64_t key; + + /* Two stages to avoid "left shift count >= width of type" warning */ + key = btbb_piconet_get_flag(pn, BTBB_IS_AFH); + key = (key<<39) | ((uint64_t)pn->used_channels<<32) | (pn->UAP<<24) | pn->LAP; + HASH_FIND(hh, hopping_map, &key, 4, s); + + if (s == NULL) { + gen_hop_pattern(pn); + s = malloc(sizeof(hopping_struct)); + s->key = key; + s->sequence = pn->sequence; + HASH_ADD(hh, hopping_map, key, 4, s); + } else { + printf("\nFound hopping sequence in cache.\n"); + pn->sequence = s->sequence; + } +} + +/* determine channel for a particular hop */ +/* borrowed from ubertooth firmware to support AFH */ +char single_hop(int clock, btbb_piconet *pn) +{ + int a, c, d, x, y1, y2, perm, next_channel; + uint32_t base_f, f, f_dash; + + /* following variable names used in section 2.6 of the spec */ + x = (clock >> 2) & 0x1f; + y1 = (clock >> 1) & 0x01; + y2 = y1 << 5; + a = (pn->a1 ^ (clock >> 21)) & 0x1f; + /* b is already defined */ + c = (pn->c1 ^ (clock >> 16)) & 0x1f; + d = (pn->d1 ^ (clock >> 7)) & 0x1ff; + /* e is already defined */ + base_f = (clock >> 3) & 0x1fffff0; + f = base_f % BT_NUM_CHANNELS; + + perm = fast_perm( + ((x + a) % 32) ^ pn->b, + (y1 * 0x1f) ^ c, + d); + /* hop selection */ + if(btbb_piconet_get_flag(pn, BTBB_IS_AFH)) { + f_dash = base_f % pn->used_channels; + next_channel = pn->bank[(perm + pn->e + f_dash + y2) % pn->used_channels]; + } else { + next_channel = pn->bank[(perm + pn->e + f + y2) % BT_NUM_CHANNELS]; + } + return next_channel; +} + +/* look up channel for a particular hop */ +char hop(int clock, btbb_piconet *pn) +{ + return pn->sequence[clock]; +} + +static char aliased_channel(char channel) +{ + return ((channel + 24) % ALIASED_CHANNELS) + 26; +} + +/* create list of initial candidate clock values (hops with same channel as first observed hop) */ +static int init_candidates(char channel, int known_clock_bits, btbb_piconet *pn) +{ + int i; + int count = 0; /* total number of candidates */ + char observable_channel; /* accounts for aliasing if necessary */ + + /* only try clock values that match our known bits */ + for (i = known_clock_bits; i < SEQUENCE_LENGTH; i += 0x40) { + if (pn->aliased) + observable_channel = aliased_channel(pn->sequence[i]); + else + observable_channel = pn->sequence[i]; + if (observable_channel == channel) + pn->clock_candidates[count++] = i; + //FIXME ought to throw exception if count gets too big + } + return count; +} + +/* initialize the hop reversal process */ +int btbb_init_hop_reversal(int aliased, btbb_piconet *pn) +{ + int max_candidates; + uint32_t clock; + + get_hop_pattern(pn); + + if(aliased) + max_candidates = (SEQUENCE_LENGTH / ALIASED_CHANNELS) / 32; + else + max_candidates = (SEQUENCE_LENGTH / BT_NUM_CHANNELS) / 32; + /* this can hold twice the approximate number of initial candidates */ + pn->clock_candidates = (uint32_t*) malloc(sizeof(uint32_t) * max_candidates); + + clock = (pn->clk_offset + pn->first_pkt_time) & 0x3f; + pn->num_candidates = init_candidates(pn->pattern_channels[0], clock, pn); + pn->winnowed = 0; + btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 1); + btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0); + btbb_piconet_set_flag(pn, BTBB_IS_ALIASED, aliased); + + printf("%d initial CLK1-27 candidates\n", pn->num_candidates); + + return pn->num_candidates; +} + +void try_hop(btbb_packet *pkt, btbb_piconet *pn) +{ + uint8_t filter_uap = pn->UAP; + + /* Decode packet - fixing clock drift in the process */ + btbb_decode(pkt, pn); + + if (btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) { + //pn->winnowed = 0; + pn->pattern_indices[pn->packets_observed] = + pkt->clkn - pn->first_pkt_time; + pn->pattern_channels[pn->packets_observed] = pkt->channel; + pn->packets_observed++; + pn->total_packets_observed++; + btbb_winnow(pn); + if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { + printf("got CLK1-27\n"); + printf("clock offset = %d.\n", pn->clk_offset); + } + } else { + if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID)) { + btbb_uap_from_header(pkt, pn); + if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { + printf("got CLK1-27\n"); + printf("clock offset = %d.\n", pn->clk_offset); + } + } else { + if (btbb_uap_from_header(pkt, pn)) { + if (filter_uap == pn->UAP) { + btbb_init_hop_reversal(0, pn); + btbb_winnow(pn); + } else { + printf("failed to confirm UAP\n"); + } + } + } + } + + if(!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) { + btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); + pn->UAP = filter_uap; + } +} + +/* return the observable channel (26-50) for a given channel (0-78) */ +/* reset UAP/clock discovery */ +static void reset(btbb_piconet *pn) +{ + //printf("no candidates remaining! starting over . . .\n"); + + if(btbb_piconet_get_flag(pn, BTBB_HOP_REVERSAL_INIT)) { + free(pn->clock_candidates); + pn->sequence = NULL; + } + btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 0); + btbb_piconet_set_flag(pn, BTBB_HOP_REVERSAL_INIT, 0); + btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 0); + btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 0); + btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 0); + pn->packets_observed = 0; + + /* + * If we have recently observed two packets in a row on the same + * channel, try AFH next time. If not, don't. + */ + btbb_piconet_set_flag(pn, BTBB_IS_AFH, + btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH)); + // btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 0); + //int i; + //for(i=0; i<10; i++) + // pn->afh_map[i] = 0; +} + +/* narrow a list of candidate clock values based on a single observed hop */ +static int channel_winnow(int offset, char channel, btbb_piconet *pn) +{ + int i; + int new_count = 0; /* number of candidates after winnowing */ + char observable_channel; /* accounts for aliasing if necessary */ + + /* check every candidate */ + for (i = 0; i < pn->num_candidates; i++) { + if (pn->aliased) + observable_channel = aliased_channel(pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]); + else + observable_channel = pn->sequence[(pn->clock_candidates[i] + offset) % SEQUENCE_LENGTH]; + if (observable_channel == channel) { + /* this candidate matches the latest hop */ + /* blow away old list of candidates with new one */ + /* safe because new_count can never be greater than i */ + pn->clock_candidates[new_count++] = pn->clock_candidates[i]; + } + } + pn->num_candidates = new_count; + + if (new_count == 1) { + // Calculate clock offset for CLKN, not CLK1-27 + pn->clk_offset = ((pn->clock_candidates[0]<<1) - (pn->first_pkt_time<<1)); + printf("\nAcquired CLK1-27 = 0x%07x\n", pn->clock_candidates[0]); + btbb_piconet_set_flag(pn, BTBB_CLK27_VALID, 1); + } + else if (new_count == 0) { + reset(pn); + } + //else { + //printf("%d CLK1-27 candidates remaining (channel=%d)\n", new_count, channel); + //} + + return new_count; +} + +/* narrow a list of candidate clock values based on all observed hops */ +int btbb_winnow(btbb_piconet *pn) +{ + int new_count = pn->num_candidates; + int index, last_index; + uint8_t channel, last_channel; + + for (; pn->winnowed < pn->packets_observed; pn->winnowed++) { + index = pn->pattern_indices[pn->winnowed]; + channel = pn->pattern_channels[pn->winnowed]; + new_count = channel_winnow(index, channel, pn); + if (new_count <= 1) + break; + + if (pn->packets_observed > 0) { + last_index = pn->pattern_indices[pn->winnowed - 1]; + last_channel = pn->pattern_channels[pn->winnowed - 1]; + /* + * Two packets in a row on the same channel should only + * happen if adaptive frequency hopping is in use. + * There can be false positives, though, especially if + * there is aliasing. + */ + if (!btbb_piconet_get_flag(pn, BTBB_LOOKS_LIKE_AFH) + && (index == last_index + 1) + && (channel == last_channel)) { + btbb_piconet_set_flag(pn, BTBB_LOOKS_LIKE_AFH, 1); + printf("Hopping pattern appears to be AFH\n"); + } + } + } + + return new_count; +} + +/* use packet headers to determine UAP */ +int btbb_uap_from_header(btbb_packet *pkt, btbb_piconet *pn) +{ + uint8_t UAP; + int count, crc_chk, first_clock = 0; + + int starting = 0; + int remaining = 0; + uint32_t clkn = pkt->clkn; + + if (!btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET)) + pn->first_pkt_time = clkn; + + // Set afh channel map + btbb_piconet_set_channel_seen(pn, pkt->channel); + + if (pn->packets_observed < MAX_PATTERN_LENGTH) { + pn->pattern_indices[pn->packets_observed] = clkn - pn->first_pkt_time; + pn->pattern_channels[pn->packets_observed] = pkt->channel; + } else { + printf("Oops. More hops than we can remember.\n"); + reset(pn); + return 0; //FIXME ought to throw exception + } + pn->packets_observed++; + pn->total_packets_observed++; + + /* try every possible first packet clock value */ + for (count = 0; count < 64; count++) { + /* skip eliminated candidates unless this is our first time through */ + if (pn->clock6_candidates[count] > -1 + || !btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET)) { + /* clock value for the current packet assuming count was the clock of the first packet */ + int clock = (count + clkn - pn->first_pkt_time) % 64; + starting++; + UAP = try_clock(clock, pkt); + crc_chk = -1; + + /* if this is the first packet: populate the candidate list */ + /* if not: check CRCs if UAPs match */ + if (!btbb_piconet_get_flag(pn, BTBB_GOT_FIRST_PACKET) + || UAP == pn->clock6_candidates[count]) + crc_chk = crc_check(clock, pkt); + + if (btbb_piconet_get_flag(pn, BTBB_UAP_VALID) && + (UAP != pn->UAP)) + crc_chk = -1; + + switch(crc_chk) { + case -1: /* UAP mismatch */ + case 0: /* CRC failure */ + pn->clock6_candidates[count] = -1; + break; + + case 1: /* inconclusive result */ + case 2: /* Inconclusive, but looks better */ + pn->clock6_candidates[count] = UAP; + /* remember this count because it may be the correct clock of the first packet */ + first_clock = count; + remaining++; + break; + + default: /* CRC success */ + pn->clk_offset = (count - (pn->first_pkt_time & 0x3f)) & 0x3f; + if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) + printf("Correct CRC! UAP = 0x%x found after %d total packets.\n", + UAP, pn->total_packets_observed); + else + printf("Correct CRC! CLK6 = 0x%x found after %d total packets.\n", + pn->clk_offset, pn->total_packets_observed); + pn->UAP = UAP; + btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1); + btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); + pn->total_packets_observed = 0; + return 1; + } + } + } + + btbb_piconet_set_flag(pn, BTBB_GOT_FIRST_PACKET, 1); + + //printf("reduced from %d to %d CLK1-6 candidates\n", starting, remaining); + + if (remaining == 1) { + pn->clk_offset = (first_clock - (pn->first_pkt_time & 0x3f)) & 0x3f; + if (!btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) + printf("UAP = 0x%x found after %d total packets.\n", + pn->clock6_candidates[first_clock], pn->total_packets_observed); + else + printf("CLK6 = 0x%x found after %d total packets.\n", + pn->clk_offset, pn->total_packets_observed); + pn->UAP = pn->clock6_candidates[first_clock]; + btbb_piconet_set_flag(pn, BTBB_CLK6_VALID, 1); + btbb_piconet_set_flag(pn, BTBB_UAP_VALID, 1); + pn->total_packets_observed = 0; + return 1; + } + + if (remaining == 0) { + reset(pn); + } + + return 0; +} + +/* FIXME: comment out enqueue and dequeue because they are + * never used. Try to find out what tey were meant to be + * used for before the next release. + */ +///* add a packet to the queue */ +//static void enqueue(btbb_packet *pkt, btbb_piconet *pn) +//{ +// pkt_queue *head; +// //pkt_queue item; +// +// btbb_packet_ref(pkt); +// pkt_queue item = {pkt, NULL}; +// head = pn->queue; +// +// if (head == NULL) { +// pn->queue = &item; +// } else { +// for(; head->next != NULL; head = head->next) +// ; +// head->next = &item; +// } +//} +// +///* pull the first packet from the queue (FIFO) */ +//static btbb_packet *dequeue(btbb_piconet *pn) +//{ +// btbb_packet *pkt; +// +// if (pn->queue == NULL) { +// pkt = NULL; +// } else { +// pkt = pn->queue->pkt; +// pn->queue = pn->queue->next; +// btbb_packet_unref(pkt); +// } +// +// return pkt; +//} + +/* decode the whole packet */ +int btbb_decode(btbb_packet* pkt, btbb_piconet *pn) +{ + btbb_packet_set_flag(pkt, BTBB_HAS_PAYLOAD, 0); + uint8_t clk6, i, best_clk; + int rv = 0, max_rv = 0; + if (btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { + /* Removing this section until we can more reliably handle AFH */ + //if(pn->sequence == NULL) + // get_hop_pattern(pn); + //clk6 = pkt->clock & 0x3f; + //for(i=0; i<64; i++) { + // pkt->clock = (pkt->clock & 0xffffffc0) | ((clk6 + i) & 0x3f); + // if ((pn->sequence[pkt->clock] == pkt->channel) && (btbb_decode_header(pkt))) { + // rv = btbb_decode_payload(pkt); + // if(rv > max_rv) { + // max_rv = rv; + // best_clk = (clk6 + i) & 0x3f; + // } + // } + //} + + // If we found nothing, try again, ignoring channel + if(max_rv <= 1) { + clk6 = pkt->clock & 0x3f; + for(i=0; i<64; i++) { + pkt->clock = (pkt->clock & 0xffffffc0) | ((clk6 + i) & 0x3f); + if (btbb_decode_header(pkt)) { + rv = btbb_decode_payload(pkt); + if(rv > max_rv) { + //printf("Packet decoded with clock 0x%07x (rv=%d)\n", pkt->clock, rv); + //btbb_print_packet(pkt); + max_rv = rv; + best_clk = (clk6 + i) & 0x3f; + } + } + } + } + } else + if (btbb_decode_header(pkt)) { + for(i=0; i<64; i++) { + pkt->clock = (pkt->clock & 0xffffffc0) | (i & 0x3f); + if (btbb_decode_header(pkt)) { + rv = btbb_decode_payload(pkt); + if(rv > max_rv) { + //printf("Packet decoded with clock 0x%02x (rv=%d)\n", i, rv); + //btbb_print_packet(pkt); + max_rv = rv; + best_clk = i & 0x3f; + } + } + } + } + /* If we were successful, print the packet */ + if(max_rv > 0) { + pkt->clock = (pkt->clock & 0xffffffc0) | (best_clk & 0x3f); + btbb_decode_payload(pkt); + printf("Packet decoded with clock 0x%02x (rv=%d)\n", i, rv); + btbb_print_packet(pkt); + } + + return max_rv; +} + +/* Print AFH map from observed packets */ +void btbb_print_afh_map(btbb_piconet *pn) { + uint8_t *afh_map; + afh_map = pn->afh_map; + + /* Print like hcitool does */ + printf("AFH map: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + afh_map[0], afh_map[1], afh_map[2], afh_map[3], afh_map[4], + afh_map[5], afh_map[6], afh_map[7], afh_map[8], afh_map[9]); + + // /* Printed ch78 -> ch0 */ + // printf("\tAFH Map=0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + // afh_map[9], afh_map[8], afh_map[7], afh_map[6], afh_map[5], + // afh_map[4], afh_map[3], afh_map[2], afh_map[1], afh_map[0]); +} + +/* Container for survey piconets */ +typedef struct { + uint32_t key; /* LAP */ + btbb_piconet *pn; + UT_hash_handle hh; +} survey_hash; + +static survey_hash *piconet_survey = NULL; + +/* Check for existing piconets in survey results */ +btbb_piconet *get_piconet(uint32_t lap) +{ + survey_hash *s; + btbb_piconet *pn; + HASH_FIND(hh, piconet_survey, &lap, 4, s); + + if (s == NULL) { + pn = btbb_piconet_new(); + btbb_init_piconet(pn, lap); + + s = malloc(sizeof(survey_hash)); + s->key = lap; + s->pn = pn; + HASH_ADD(hh, piconet_survey, key, 4, s); + } else { + pn = s->pn; + } + return pn; +} + +/* Destructively iterate over survey results */ +btbb_piconet *btbb_next_survey_result() { + btbb_piconet *pn = NULL; + survey_hash *tmp; + + if (piconet_survey != NULL) { + pn = piconet_survey->pn; + tmp = piconet_survey; + piconet_survey = piconet_survey->hh.next; + free(tmp); + } + return pn; +} + +int btbb_process_packet(btbb_packet *pkt, btbb_piconet *pn) { + if (survey_mode) { + pn = get_piconet(btbb_packet_get_lap(pkt)); + btbb_piconet_set_channel_seen(pn, pkt->channel); + if(btbb_header_present(pkt) && !btbb_piconet_get_flag(pn, BTBB_UAP_VALID)) + btbb_uap_from_header(pkt, pn); + return 0; + } + + if(pn) + btbb_piconet_set_channel_seen(pn, pkt->channel); + + /* If piconet structure is given, a LAP is given, and packet + * header is readable, do further analysis. If UAP has not yet + * been determined, attempt to calculate it from headers. Once + * UAP is known, try to determine clk6 and clk27. Once clocks + * are known, follow the piconet. */ + if (pn && btbb_piconet_get_flag(pn, BTBB_LAP_VALID) && + btbb_header_present(pkt)) { + + /* Have LAP/UAP/clocks, now hopping along with the piconet. */ + if (btbb_piconet_get_flag(pn, BTBB_FOLLOWING)) { + btbb_packet_set_uap(pkt, btbb_piconet_get_uap(pn)); + btbb_packet_set_flag(pkt, BTBB_CLK6_VALID, 1); + btbb_packet_set_flag(pkt, BTBB_CLK27_VALID, 1); + + if(btbb_decode(pkt, pn)) + btbb_print_packet(pkt); + else + printf("Failed to decode packet\n"); + } + + /* Have LAP/UAP, need clocks. */ + else if (btbb_piconet_get_uap(pn)) { + try_hop(pkt, pn); + if (btbb_piconet_get_flag(pn, BTBB_CLK6_VALID) && + btbb_piconet_get_flag(pn, BTBB_CLK27_VALID)) { + btbb_piconet_set_flag(pn, BTBB_FOLLOWING, 1); + return -1; + } + } + + /* Have LAP, need UAP. */ + else { + btbb_uap_from_header(pkt, pn); + } + } + return 0; +} diff --git a/libbtbb-2015-10-R1/lib/src/bluetooth_piconet.h b/libbtbb-2015-10-R1/lib/src/bluetooth_piconet.h new file mode 100644 index 0000000..3652a33 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/bluetooth_piconet.h @@ -0,0 +1,131 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_BLUETOOTH_PICONET_H +#define INCLUDED_BLUETOOTH_PICONET_H +#include "btbb.h" + +/* maximum number of hops to remember */ +#define MAX_PATTERN_LENGTH 1000 + +/* number of channels in use */ +#define BT_NUM_CHANNELS 79 + +struct btbb_piconet { + + uint32_t refcount; + + uint32_t flags; + + /* true if using a particular aliased receiver implementation */ + int aliased; + + /* AFH channel map - either read or derived from observed packets */ + uint8_t afh_map[10]; + + /* Number of used channel derived from AFH channel map */ + uint8_t used_channels; + + /* lower address part (of master's BD_ADDR) */ + uint32_t LAP; + + /* upper address part (of master's BD_ADDR) */ + uint8_t UAP; + + /* non-significant address part (of master's BD_ADDR) */ + uint16_t NAP; + + /* CLK1-27 candidates */ + uint32_t *clock_candidates; + + /* these values for hop() can be precalculated */ + int b, e; + + /* these values for hop() can be precalculated in part (e.g. a1 is the + * precalculated part of a) */ + int a1, c1, d1; + + /* frequency register bank */ + int bank[BT_NUM_CHANNELS]; + + /* this holds the entire hopping sequence */ + char *sequence; + + /* number of candidates for CLK1-27 */ + int num_candidates; + + /* number of packets observed during one attempt at UAP/clock discovery */ + int packets_observed; + + /* total number of packets observed */ + int total_packets_observed; + + /* number of observed packets that have been used to winnow the candidates */ + int winnowed; + + /* CLK1-6 candidates */ + int clock6_candidates[64]; + + /* remember patterns of observed hops */ + int pattern_indices[MAX_PATTERN_LENGTH]; + uint8_t pattern_channels[MAX_PATTERN_LENGTH]; + + /* offset between CLKN (local) and CLK of piconet */ + int clk_offset; + + /* local clock (clkn) at time of first packet */ + uint32_t first_pkt_time; + + /* queue of packets to be decoded */ + pkt_queue *queue; +}; + +/* number of hops in the hopping sequence (i.e. number of possible values of CLK1-27) */ +#define SEQUENCE_LENGTH 134217728 + +/* number of aliased channels received */ +#define ALIASED_CHANNELS 25 + +/* do all the precalculation that can be done before knowing the address */ +void precalc(btbb_piconet *pnet); + +/* do precalculation that requires the address */ +void address_precalc(int address, btbb_piconet *pnet); + +/* drop-in replacement for perm5() using lookup table */ +int fast_perm(int z, int p_high, int p_low); + +/* 5 bit permutation */ +/* assumes z is constrained to 5 bits, p_high to 5 bits, p_low to 9 bits */ +int perm5(int z, int p_high, int p_low); + +/* determine channel for a particular hop */ +/* replaced with gen_hops() for a complete sequence but could still come in handy */ +char single_hop(int clock, btbb_piconet *pnet); + +/* look up channel for a particular hop */ +char hop(int clock, btbb_piconet *pnet); + +void try_hop(btbb_packet *pkt, btbb_piconet *pn); + +void get_hop_pattern(btbb_piconet *pn); + +#endif /* INCLUDED_BLUETOOTH_PICONET_H */ diff --git a/libbtbb-2015-10-R1/lib/src/btbb.h b/libbtbb-2015-10-R1/lib/src/btbb.h new file mode 100644 index 0000000..154775c --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/btbb.h @@ -0,0 +1,288 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2013 Dominic Spill, Michael Ossmann, Will Code + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_BTBB_H +#define INCLUDED_BTBB_H + +#include + +#define BTBB_WHITENED 0 +#define BTBB_NAP_VALID 1 +#define BTBB_UAP_VALID 2 +#define BTBB_LAP_VALID 3 +#define BTBB_CLK6_VALID 4 +#define BTBB_CLK27_VALID 5 +#define BTBB_CRC_CORRECT 6 +#define BTBB_HAS_PAYLOAD 7 +#define BTBB_IS_EDR 8 + +#define BTBB_HOP_REVERSAL_INIT 9 +#define BTBB_GOT_FIRST_PACKET 10 +#define BTBB_IS_AFH 11 +#define BTBB_LOOKS_LIKE_AFH 12 +#define BTBB_IS_ALIASED 13 +#define BTBB_FOLLOWING 14 + +/* Payload modulation */ +#define BTBB_MOD_UNKNOWN 0x00 +#define BTBB_MOD_GFSK 0x01 +#define BTBB_MOD_PI_OVER_2_DQPSK 0x02 +#define BTBB_MOD_8DPSK 0x03 + +/* Transport types */ +#define BTBB_TRANSPORT_ANY 0x00 +#define BTBB_TRANSPORT_SCO 0x01 +#define BTBB_TRANSPORT_ESCO 0x02 +#define BTBB_TRANSPORT_ACL 0x03 +#define BTBB_TRANSPORT_CSB 0x04 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* BT BR/EDR support */ + +typedef struct btbb_packet btbb_packet; + +/* Initialize the library. Compute the syndrome. Return 0 on success, + * negative on error. + * + * The library limits max_ac_errors to 5. Using a larger value will + * take up a lot of memory (several GB), without decoding many useful + * packets. Even a limit of 5 results in a syndrome table of several + * hundred MB and lots of noise. For embedded targets, a value of 2 is + * reasonable. */ +int btbb_init(int max_ac_errors); + +char *btbb_get_release(void); +char *btbb_get_version(void); + +btbb_packet *btbb_packet_new(void); +void btbb_packet_ref(btbb_packet *pkt); +void btbb_packet_unref(btbb_packet *pkt); + +/* Search for a packet with specified LAP (or LAP_ANY). The stream + * must be at least of length serch_length + 72. Limit to + * 'max_ac_errors' bit errors. + * + * Returns offset into 'stream' at which packet was found. If no + * packet was found, returns a negative number. If LAP_ANY was + * specified, fills lap. 'ac_errors' must be set as an input, replaced + * by actual number of errors on output. */ +int btbb_find_ac(char *stream, + int search_length, + uint32_t lap, + int max_ac_errors, + btbb_packet **pkt); +#define LAP_ANY 0xffffffffUL +#define UAP_ANY 0xff + +void btbb_packet_set_flag(btbb_packet *pkt, int flag, int val); +int btbb_packet_get_flag(const btbb_packet *pkt, int flag); + +uint32_t btbb_packet_get_lap(const btbb_packet *pkt); +void btbb_packet_set_uap(btbb_packet *pkt, uint8_t uap); +uint8_t btbb_packet_get_uap(const btbb_packet *pkt); +uint16_t btbb_packet_get_nap(const btbb_packet *pkt); + +void btbb_packet_set_modulation(btbb_packet *pkt, uint8_t modulation); +void btbb_packet_set_transport(btbb_packet *pkt, uint8_t transport); +uint8_t btbb_packet_get_modulation(const btbb_packet *pkt); +uint8_t btbb_packet_get_transport(const btbb_packet *pkt); + +uint8_t btbb_packet_get_channel(const btbb_packet *pkt); +uint8_t btbb_packet_get_ac_errors(const btbb_packet *pkt); +uint32_t btbb_packet_get_clkn(const btbb_packet *pkt); +uint32_t btbb_packet_get_header_packed(const btbb_packet* pkt); + +void btbb_packet_set_data(btbb_packet *pkt, + char *syms, // Symbol data + int length, // Number of symbols + uint8_t channel, // Bluetooth channel 0-79 + uint32_t clkn); // 312.5us clock (CLK27-0) + +/* Get a pointer to packet symbols. */ +const char *btbb_get_symbols(const btbb_packet* pkt); + +int btbb_packet_get_payload_length(const btbb_packet* pkt); + +/* Get a pointer to payload. */ +const char *btbb_get_payload(const btbb_packet* pkt); + +/* Pack the payload in to bytes */ +int btbb_get_payload_packed(const btbb_packet* pkt, char *dst); + +uint8_t btbb_packet_get_type(const btbb_packet* pkt); +uint8_t btbb_packet_get_lt_addr(const btbb_packet* pkt); +uint8_t btbb_packet_get_header_flags(const btbb_packet* pkt); +uint8_t btbb_packet_get_hec(const btbb_packet *pkt); + +/* Generate Sync Word from an LAP */ +uint64_t btbb_gen_syncword(const int LAP); + +/* decode the packet header */ +int btbb_decode_header(btbb_packet* pkt); + +/* decode the packet header */ +int btbb_decode_payload(btbb_packet* pkt); + +/* print packet information */ +void btbb_print_packet(const btbb_packet* pkt); + +/* check to see if the packet has a header */ +int btbb_header_present(const btbb_packet* pkt); + +/* Packet queue (linked list) */ +typedef struct pkt_queue { + btbb_packet *pkt; + + struct pkt_queue *next; + +} pkt_queue; + +typedef struct btbb_piconet btbb_piconet; + +btbb_piconet *btbb_piconet_new(void); +void btbb_piconet_ref(btbb_piconet *pn); +void btbb_piconet_unref(btbb_piconet *pn); + +/* initialize the piconet struct */ +void btbb_init_piconet(btbb_piconet *pn, uint32_t lap); + +void btbb_piconet_set_uap(btbb_piconet *pn, uint8_t uap); +uint8_t btbb_piconet_get_uap(const btbb_piconet *pn); +uint32_t btbb_piconet_get_lap(const btbb_piconet *pn); +uint16_t btbb_piconet_get_nap(const btbb_piconet *pn); +uint64_t btbb_piconet_get_bdaddr(const btbb_piconet *pn); + +int btbb_piconet_get_clk_offset(const btbb_piconet *pn); +void btbb_piconet_set_clk_offset(btbb_piconet *pn, int clk_offset); + +void btbb_piconet_set_flag(btbb_piconet *pn, int flag, int val); +int btbb_piconet_get_flag(const btbb_piconet *pn, int flag); + +void btbb_piconet_set_channel_seen(btbb_piconet *pn, uint8_t channel); +void btbb_piconet_set_afh_map(btbb_piconet *pn, uint8_t *afh_map); +uint8_t *btbb_piconet_get_afh_map(btbb_piconet *pn); + +/* Extract as much information (LAP/UAP/CLK) as possible from received packet */ +int btbb_process_packet(btbb_packet *pkt, btbb_piconet *pn); + +/* use packet headers to determine UAP */ +int btbb_uap_from_header(btbb_packet *pkt, btbb_piconet *pn); + +/* Print hexadecimal representation of the derived AFH map */ +void btbb_print_afh_map(btbb_piconet *pn); + +/* decode a whole packet from the given piconet */ +int btbb_decode(btbb_packet* pkt, btbb_piconet *pn); + + +/* initialize the hop reversal process */ +/* returns number of initial candidates for CLK1-27 */ +int btbb_init_hop_reversal(int aliased, btbb_piconet *pn); + +/* narrow a list of candidate clock values based on all observed hops */ +int btbb_winnow(btbb_piconet *pn); + +int btbb_init_survey(void); +/* Destructively iterate over survey results - optionally remove elements */ +btbb_piconet *btbb_next_survey_result(void); + +typedef struct btbb_pcapng_handle btbb_pcapng_handle; +/* create a PCAPNG file for BREDR captures */ +int btbb_pcapng_create_file(const char *filename, const char *interface_desc, btbb_pcapng_handle ** ph); +/* save a BREDR packet to PCAPNG capture file */ +int btbb_pcapng_append_packet(btbb_pcapng_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t reflap, const uint8_t refuap, + const btbb_packet *pkt); +/* record a BDADDR to PCAPNG capture file */ +int btbb_pcapng_record_bdaddr(btbb_pcapng_handle * h, const uint64_t bdaddr, + const uint8_t uapmask, const uint8_t napvalid); +/* record BT CLOCK to PCAPNG capture file */ +int btbb_pcapng_record_btclock(btbb_pcapng_handle * h, const uint64_t bdaddr, + const uint64_t ns, const uint32_t clk, const uint32_t clkmask); +int btbb_pcapng_close(btbb_pcapng_handle * h); + + +/* BLE support */ +typedef struct lell_packet lell_packet; +/* decode and allocate LE packet */ +void lell_allocate_and_decode(const uint8_t *stream, uint16_t phys_channel, uint32_t clk100ns, lell_packet **pkt); +lell_packet *lell_packet_new(void); +void lell_packet_ref(lell_packet *pkt); +void lell_packet_unref(lell_packet *pkt); +uint32_t lell_get_access_address(const lell_packet *pkt); +unsigned lell_get_access_address_offenses(const lell_packet *pkt); +unsigned lell_packet_is_data(const lell_packet *pkt); +unsigned lell_get_channel_index(const lell_packet *pkt); +unsigned lell_get_channel_k(const lell_packet *pkt); +const char * lell_get_adv_type_str(const lell_packet *pkt); +void lell_print(const lell_packet *pkt); + +typedef struct lell_pcapng_handle lell_pcapng_handle; +/* create a PCAPNG file for LE captures */ +int lell_pcapng_create_file(const char *filename, const char *interface_desc, lell_pcapng_handle ** ph); +/* save an LE packet to PCAPNG capture file */ +int lell_pcapng_append_packet(lell_pcapng_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t refAA, const lell_packet *pkt); +/* record LE CONNECT_REQ parameters to PCAPNG capture file */ +int lell_pcapng_record_connect_req(lell_pcapng_handle * h, const uint64_t ns, const uint8_t * pdu); +int lell_pcapng_close(lell_pcapng_handle *h); + + +/* PCAP Support */ +#if defined(ENABLE_PCAP) +typedef struct btbb_pcap_handle btbb_pcap_handle; +/* create a PCAP file for BREDR captures with LINKTYPE_BLUETOOTH_BREDR_BB */ +int btbb_pcap_create_file(const char *filename, btbb_pcap_handle ** ph); +/* write a BREDR packet to PCAP file */ +int btbb_pcap_append_packet(btbb_pcap_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t reflap, const uint8_t refuap, + const btbb_packet *pkt); +int btbb_pcap_close(btbb_pcap_handle * h); + +typedef struct lell_pcap_handle lell_pcap_handle; +/* create a PCAP file for LE captures using LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR */ +int lell_pcap_create_file(const char *filename, lell_pcap_handle ** ph); +/* create a PCAP file for LE captures using LINKTYPE_PPI */ +int lell_pcap_ppi_create_file(const char *filename, int btle_ppi_version, lell_pcap_handle ** ph); +/* save an LE packet to PCAP capture file */ +int lell_pcap_append_packet(lell_pcap_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t refAA, const lell_packet *pkt); +int lell_pcap_append_ppi_packet(lell_pcap_handle * h, const uint64_t ns, + const uint8_t clkn_high, + const int8_t rssi_min, const int8_t rssi_max, + const int8_t rssi_avg, const uint8_t rssi_count, + const lell_packet *pkt); +int lell_pcap_close(lell_pcap_handle *h); +#endif // ENABLE_PCAP + +#ifdef __cplusplus +} // __cplusplus defined. +#endif + +#endif /* INCLUDED_BTBB_H */ diff --git a/libbtbb-2015-10-R1/lib/src/pcap-common.h b/libbtbb-2015-10-R1/lib/src/pcap-common.h new file mode 100644 index 0000000..29856f6 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/pcap-common.h @@ -0,0 +1,129 @@ +/* -*- c -*- */ +/* + * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef PCAP_COMMON_DOT_H +#define PCAP_COMMON_DOT_H + +/* pull definitions for BT DLTs and pseudoheaders from libpcap, if possible */ +#if defined(ENABLE_PCAP) +#include +#include +#endif /* ENABLE_PCAP */ + +#if defined( __APPLE__ ) +#include +#define htobe32 EndianU32_NtoB +#define be32toh EndianU32_BtoN +#define le32toh EndianU32_LtoN +#define htobe64 EndianU64_NtoB +#define be64toh EndianU64_BtoN +#define htole16 EndianU16_NtoL +#define htole32 EndianU32_NtoL +#else +#include +#endif + +#if !defined( htole16 ) /* will be defined under Linux when endian.h already included */ +#if defined( __GNUC__ ) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +inline uint16_t htole16(uint16_t host_16bits) { return host_16bits; } +inline uint16_t le16toh(uint16_t little_endian_16bits) { return little_endian_16bits; } +inline uint32_t htole32(uint32_t host_32bits) { return host_32bits; } +inline uint32_t le32toh(uint32_t little_endian_32bits) { return little_endian_32bits; } +inline uint64_t htole64(uint64_t host_64bits) { return host_64bits; } +inline uint64_t le64toh(uint64_t little_endian_64bits) { return little_endian_64bits; } +#else +#error "FIXME: need to support big-endian under GNU" +#endif /* __BYTE_ORDER__ */ +#else /* not GNU C */ +#error "FIXME: need to support non-GNU compiler" +#endif /* __GNUC__ */ +#endif /* htole16 */ + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +/* --------------------------------- BR/EDR ----------------------------- */ + +#if !defined( DLT_BLUETOOTH_BREDR_BB ) +#define DLT_BLUETOOTH_BREDR_BB 255 +#endif +typedef struct __attribute__((packed)) _pcap_bluetooth_bredr_bb_header { + uint8_t rf_channel; + int8_t signal_power; + int8_t noise_power; + uint8_t access_code_offenses; + uint8_t payload_transport_rate; + uint8_t corrected_header_bits; + int16_t corrected_payload_bits; + uint32_t lap; + uint32_t ref_lap_uap; + uint32_t bt_header; + uint16_t flags; + uint8_t br_edr_payload[0]; +} pcap_bluetooth_bredr_bb_header; + +#define BREDR_DEWHITENED 0x0001 +#define BREDR_SIGPOWER_VALID 0x0002 +#define BREDR_NOISEPOWER_VALID 0x0004 +#define BREDR_PAYLOAD_DECRYPTED 0x0008 +#define BREDR_REFLAP_VALID 0x0010 +#define BREDR_PAYLOAD_PRESENT 0x0020 +#define BREDR_CHANNEL_ALIASED 0x0040 +#define BREDR_REFUAP_VALID 0x0080 +#define BREDR_HEC_CHECKED 0x0100 +#define BREDR_HEC_VALID 0x0200 +#define BREDR_CRC_CHECKED 0x0400 +#define BREDR_CRC_VALID 0x0800 +#define BREDR_MIC_CHECKED 0x1000 +#define BREDR_MIC_VALID 0x2000 + +#define BREDR_MAX_PAYLOAD 400 + +/* --------------------------------- Low Energy ---------------------------- */ + +#if !defined( DLT_BLUETOOTH_LE_LL_WITH_PHDR ) +#define DLT_BLUETOOTH_LE_LL_WITH_PHDR 256 +#endif +typedef struct __attribute__((packed)) _pcap_bluetooth_le_ll_header { + uint8_t rf_channel; + int8_t signal_power; + int8_t noise_power; + uint8_t access_address_offenses; + uint32_t ref_access_address; + uint16_t flags; + uint8_t le_packet[0]; +} pcap_bluetooth_le_ll_header; + +#define LE_DEWHITENED 0x0001 +#define LE_SIGPOWER_VALID 0x0002 +#define LE_NOISEPOWER_VALID 0x0004 +#define LE_PACKET_DECRYPTED 0x0008 +#define LE_REF_AA_VALID 0x0010 +#define LE_AA_OFFENSES_VALID 0x0020 +#define LE_CHANNEL_ALIASED 0x0040 +#define LE_CRC_CHECKED 0x0400 +#define LE_CRC_VALID 0x0800 +#define LE_MIC_CHECKED 0x1000 +#define LE_MIC_VALID 0x2000 + +#define LE_MAX_PAYLOAD 48 + +#endif /* PCAP_COMMON_DOT_H */ diff --git a/libbtbb-2015-10-R1/lib/src/pcap.c b/libbtbb-2015-10-R1/lib/src/pcap.c new file mode 100644 index 0000000..77da261 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/pcap.c @@ -0,0 +1,422 @@ +/* -*- c -*- */ +/* + * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#include "bluetooth_le_packet.h" +#include "bluetooth_packet.h" +#include "btbb.h" +#include "pcap-common.h" + +#include +#include + +typedef enum { + PCAP_OK = 0, + PCAP_INVALID_HANDLE, + PCAP_FILE_NOT_ALLOWED, + PCAP_NO_MEMORY, +} PCAP_RESULT; + +#if defined(ENABLE_PCAP) + +/* BT BR/EDR support */ + +struct btbb_pcap_handle { + pcap_t * pcap; + pcap_dumper_t * dumper; +}; + +int +btbb_pcap_create_file(const char *filename, btbb_pcap_handle ** ph) +{ + int retval = 0; + btbb_pcap_handle * handle = malloc( sizeof(btbb_pcap_handle) ); + if (handle) { + memset(handle, 0, sizeof(*handle)); +#ifdef PCAP_TSTAMP_PRECISION_NANO + handle->pcap = pcap_open_dead_with_tstamp_precision(DLT_BLUETOOTH_BREDR_BB, + BREDR_MAX_PAYLOAD, + PCAP_TSTAMP_PRECISION_NANO); +#else + handle->pcap = pcap_open_dead(DLT_BLUETOOTH_BREDR_BB, BREDR_MAX_PAYLOAD); +#endif + if (handle->pcap) { + handle->dumper = pcap_dump_open(handle->pcap, filename); + if (handle->dumper) { + *ph = handle; + } + else { + pcap_perror(handle->pcap, "PCAP error:"); + retval = -PCAP_FILE_NOT_ALLOWED; + goto fail; + } + } + else { + retval = -PCAP_INVALID_HANDLE; + goto fail; + } + } + else { + retval = -PCAP_NO_MEMORY; + goto fail; + } + return retval; +fail: + (void) btbb_pcap_close( handle ); + return retval; +} + +typedef struct { + struct pcap_pkthdr pcap_header; + pcap_bluetooth_bredr_bb_header bredr_bb_header; + uint8_t bredr_payload[BREDR_MAX_PAYLOAD]; +} pcap_bredr_packet; + +static void +assemble_pcapng_bredr_packet( pcap_bredr_packet * pkt, + const uint32_t interface_id __attribute__((unused)), + const uint64_t ns, + const uint32_t caplen, + const uint8_t rf_channel, + const int8_t signal_power, + const int8_t noise_power, + const uint8_t access_code_offenses, + const uint8_t payload_transport, + const uint8_t payload_rate, + const uint8_t corrected_header_bits, + const int16_t corrected_payload_bits, + const uint32_t lap, + const uint32_t ref_lap, + const uint8_t ref_uap, + const uint32_t bt_header, + const uint16_t flags, + const uint8_t * payload ) +{ + uint32_t pcap_caplen = sizeof(pcap_bluetooth_bredr_bb_header)+caplen; + uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24); + + pkt->pcap_header.ts.tv_sec = ns / 1000000000ull; + pkt->pcap_header.ts.tv_usec = ns % 1000000000ull; + pkt->pcap_header.caplen = pcap_caplen; + pkt->pcap_header.len = pcap_caplen; + + pkt->bredr_bb_header.rf_channel = rf_channel; + pkt->bredr_bb_header.signal_power = signal_power; + pkt->bredr_bb_header.noise_power = noise_power; + pkt->bredr_bb_header.access_code_offenses = access_code_offenses; + pkt->bredr_bb_header.payload_transport_rate = + (payload_transport << 4) | payload_rate; + pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits; + pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits ); + pkt->bredr_bb_header.lap = htole32( lap ); + pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap ); + pkt->bredr_bb_header.bt_header = htole16( bt_header ); + pkt->bredr_bb_header.flags = htole16( flags ); + if (caplen) { + (void) memcpy( &pkt->bredr_payload[0], payload, caplen ); + } + else { + pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT ); + } +} + +int +btbb_pcap_append_packet(btbb_pcap_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t reflap, const uint8_t refuap, + const btbb_packet *pkt) +{ + if (h && h->dumper) { + uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID | + ((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) | + ((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) | + ((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0); + uint32_t caplen = (uint32_t) btbb_packet_get_payload_length(pkt); + uint8_t payload_bytes[caplen]; + btbb_get_payload_packed( pkt, (char *) &payload_bytes[0] ); + caplen = MIN(BREDR_MAX_PAYLOAD, caplen); + pcap_bredr_packet pcap_pkt; + assemble_pcapng_bredr_packet( &pcap_pkt, + 0, + ns, + caplen, + btbb_packet_get_channel(pkt), + sigdbm, + noisedbm, + btbb_packet_get_ac_errors(pkt), + btbb_packet_get_transport(pkt), + btbb_packet_get_modulation(pkt), + 0, /* TODO: corrected header bits */ + 0, /* TODO: corrected payload bits */ + btbb_packet_get_lap(pkt), + reflap, + refuap, + btbb_packet_get_header_packed(pkt), + flags, + payload_bytes ); + pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.bredr_bb_header); + return 0; + } + return -PCAP_INVALID_HANDLE; +} + +int +btbb_pcap_close(btbb_pcap_handle * h) +{ + if (h && h->dumper) { + pcap_dump_close(h->dumper); + } + if (h && h->pcap) { + pcap_close(h->pcap); + } + if (h) { + free(h); + return 0; + } + return -PCAP_INVALID_HANDLE; +} + +/* BTLE support */ + +struct lell_pcap_handle { + pcap_t * pcap; + pcap_dumper_t * dumper; + int dlt; + uint8_t btle_ppi_version; +}; + +static int +lell_pcap_create_file_dlt(const char *filename, int dlt, lell_pcap_handle ** ph) +{ + int retval = 0; + lell_pcap_handle * handle = malloc( sizeof(lell_pcap_handle) ); + if (handle) { + memset(handle, 0, sizeof(*handle)); +#ifdef PCAP_TSTAMP_PRECISION_NANO + handle->pcap = pcap_open_dead_with_tstamp_precision(dlt, + BREDR_MAX_PAYLOAD, + PCAP_TSTAMP_PRECISION_NANO); +#else + handle->pcap = pcap_open_dead(dlt, BREDR_MAX_PAYLOAD); +#endif + if (handle->pcap) { + handle->dumper = pcap_dump_open(handle->pcap, filename); + if (handle->dumper) { + handle->dlt = dlt; + *ph = handle; + } + else { + retval = -PCAP_FILE_NOT_ALLOWED; + goto fail; + } + } + else { + retval = -PCAP_INVALID_HANDLE; + goto fail; + } + } + else { + retval = -PCAP_NO_MEMORY; + goto fail; + } + return retval; +fail: + (void) lell_pcap_close( handle ); + return retval; +} + +int +lell_pcap_create_file(const char *filename, lell_pcap_handle ** ph) +{ + return lell_pcap_create_file_dlt(filename, DLT_BLUETOOTH_LE_LL_WITH_PHDR, ph); +} + +int +lell_pcap_ppi_create_file(const char *filename, int btle_ppi_version, + lell_pcap_handle ** ph) +{ + int retval = lell_pcap_create_file_dlt(filename, DLT_PPI, ph); + if (!retval) { + (*ph)->btle_ppi_version = btle_ppi_version; + } + return retval; +} + +typedef struct { + struct pcap_pkthdr pcap_header; + pcap_bluetooth_le_ll_header le_ll_header; + uint8_t le_packet[LE_MAX_PAYLOAD]; +} pcap_le_packet; + +static void +assemble_pcapng_le_packet( pcap_le_packet * pkt, + const uint32_t interface_id __attribute__((unused)), + const uint64_t ns, + const uint32_t caplen, + const uint8_t rf_channel, + const int8_t signal_power, + const int8_t noise_power, + const uint8_t access_address_offenses, + const uint32_t ref_access_address, + const uint16_t flags, + const uint8_t * lepkt ) +{ + uint32_t pcap_caplen = sizeof(pcap_bluetooth_le_ll_header)+caplen; + + pkt->pcap_header.ts.tv_sec = ns / 1000000000ull; + pkt->pcap_header.ts.tv_usec = ns % 1000000000ull; + pkt->pcap_header.caplen = pcap_caplen; + pkt->pcap_header.len = pcap_caplen; + + pkt->le_ll_header.rf_channel = rf_channel; + pkt->le_ll_header.signal_power = signal_power; + pkt->le_ll_header.noise_power = noise_power; + pkt->le_ll_header.access_address_offenses = access_address_offenses; + pkt->le_ll_header.ref_access_address = htole32( ref_access_address ); + pkt->le_ll_header.flags = htole16( flags ); + (void) memcpy( &pkt->le_packet[0], lepkt, caplen ); +} + +int +lell_pcap_append_packet(lell_pcap_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t refAA, const lell_packet *pkt) +{ + if (h && h->dumper && + (h->dlt == DLT_BLUETOOTH_LE_LL_WITH_PHDR)) { + uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID | + LE_SIGPOWER_VALID | + ((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) | + (lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID); + pcap_le_packet pcap_pkt; + assemble_pcapng_le_packet( &pcap_pkt, + 0, + ns, + 9+pkt->length, + pkt->channel_k, + sigdbm, + noisedbm, + pkt->access_address_offenses, + refAA, + flags, + &pkt->symbols[0] ); + pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.le_ll_header); + return 0; + } + return -PCAP_INVALID_HANDLE; +} + +#define PPI_BTLE 30006 + +typedef struct __attribute__((packed)) { + uint8_t pph_version; + uint8_t pph_flags; + uint16_t pph_len; + uint32_t pph_dlt; +} ppi_packet_header_t; + +typedef struct __attribute__((packed)) { + uint16_t pfh_type; + uint16_t pfh_datalen; +} ppi_fieldheader_t; + +typedef struct __attribute__((packed)) { + uint8_t btle_version; + uint16_t btle_channel; + uint8_t btle_clkn_high; + uint32_t btle_clk100ns; + int8_t rssi_max; + int8_t rssi_min; + int8_t rssi_avg; + uint8_t rssi_count; +} ppi_btle_t; + +typedef struct __attribute__((packed)) { + struct pcap_pkthdr pcap_header; + ppi_packet_header_t ppi_packet_header; + ppi_fieldheader_t ppi_fieldheader; + ppi_btle_t le_ll_ppi_header; + uint8_t le_packet[LE_MAX_PAYLOAD]; +} pcap_ppi_le_packet; + +int +lell_pcap_append_ppi_packet(lell_pcap_handle * h, const uint64_t ns, + const uint8_t clkn_high, + const int8_t rssi_min, const int8_t rssi_max, + const int8_t rssi_avg, const uint8_t rssi_count, + const lell_packet *pkt) +{ + const uint16_t ppi_packet_header_sz = sizeof(ppi_packet_header_t); + const uint16_t ppi_fieldheader_sz = sizeof(ppi_fieldheader_t); + const uint16_t le_ll_ppi_header_sz = sizeof(ppi_btle_t); + + if (h && h->dumper && + (h->dlt == DLT_PPI)) { + pcap_ppi_le_packet pcap_pkt; + uint32_t pcap_caplen = + ppi_packet_header_sz+ppi_fieldheader_sz+le_ll_ppi_header_sz+pkt->length+9; + uint16_t MHz = 2402 + 2*lell_get_channel_k(pkt); + + pcap_pkt.pcap_header.ts.tv_sec = ns / 1000000000ull; + pcap_pkt.pcap_header.ts.tv_usec = ns % 1000000000ull; + pcap_pkt.pcap_header.caplen = pcap_caplen; + pcap_pkt.pcap_header.len = pcap_caplen; + + pcap_pkt.ppi_packet_header.pph_version = 0; + pcap_pkt.ppi_packet_header.pph_flags = 0; + pcap_pkt.ppi_packet_header.pph_len = htole16(ppi_packet_header_sz+ppi_fieldheader_sz+le_ll_ppi_header_sz); + pcap_pkt.ppi_packet_header.pph_dlt = htole32(DLT_USER0); + + pcap_pkt.ppi_fieldheader.pfh_type = htole16(PPI_BTLE); + pcap_pkt.ppi_fieldheader.pfh_datalen = htole16(le_ll_ppi_header_sz); + + pcap_pkt.le_ll_ppi_header.btle_version = h->btle_ppi_version; + pcap_pkt.le_ll_ppi_header.btle_channel = htole16(MHz); + pcap_pkt.le_ll_ppi_header.btle_clkn_high = clkn_high; + pcap_pkt.le_ll_ppi_header.btle_clk100ns = htole32(pkt->clk100ns); + pcap_pkt.le_ll_ppi_header.rssi_max = rssi_max; + pcap_pkt.le_ll_ppi_header.rssi_min = rssi_min; + pcap_pkt.le_ll_ppi_header.rssi_avg = rssi_avg; + pcap_pkt.le_ll_ppi_header.rssi_count = rssi_count; + (void) memcpy( &pcap_pkt.le_packet[0], &pkt->symbols[0], pkt->length + 9 ); // FIXME where does the 9 come from? + pcap_dump((u_char *)h->dumper, &pcap_pkt.pcap_header, (u_char *)&pcap_pkt.ppi_packet_header); + pcap_dump_flush(h->dumper); + return 0; + } + return -PCAP_INVALID_HANDLE; +} + +int +lell_pcap_close(lell_pcap_handle *h) +{ + if (h && h->dumper) { + pcap_dump_close(h->dumper); + } + if (h && h->pcap) { + pcap_close(h->pcap); + } + if (h) { + free(h); + return 0; + } + return -PCAP_INVALID_HANDLE; +} + +#endif /* ENABLE_PCAP */ diff --git a/libbtbb-2015-10-R1/lib/src/pcapng-bt.c b/libbtbb-2015-10-R1/lib/src/pcapng-bt.c new file mode 100644 index 0000000..b969a6a --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/pcapng-bt.c @@ -0,0 +1,522 @@ +/* -*- c -*- */ +/* + * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "btbb.h" +#include "bluetooth_le_packet.h" +#include "bluetooth_packet.h" +#include "pcapng-bt.h" +#include +#include +#include +#include +#include +#include + +/* generic section options indicating libbtbb */ +const struct { + struct { + option_header hdr; + char libname[8]; + } libopt; + struct { + option_header hdr; + } termopt; +} libbtbb_section_options = { + .libopt = { + .hdr = { + .option_code = SHB_USERAPPL, + .option_length = 7 }, + .libname = "libbtbb" + }, + .termopt = { + .hdr = { + .option_code = OPT_ENDOFOPT, + .option_length = 0 + } + } +}; + +static PCAPNG_RESULT +check_and_fix_tsresol( PCAPNG_HANDLE * handle, + const option_header * interface_options ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + int got_tsresol = 0; + + while( !got_tsresol && + interface_options && + interface_options->option_code && + interface_options->option_length) { + if (interface_options->option_code == IF_TSRESOL) { + got_tsresol = 1; + } + else { + size_t step = 4+4*((interface_options->option_length+3)/4); + uint8_t * next = &((uint8_t *)interface_options)[step]; + interface_options = (const option_header *) next; + } + } + + if (!got_tsresol) { + const struct { + option_header hdr; + uint8_t resol; + } tsresol = { + .hdr = { + .option_code = IF_TSRESOL, + .option_length = 1, + }, + .resol = 9 /* 10^-9 is nanoseconds */ + }; + + retval = pcapng_append_interface_option( handle, + (const option_header *) &tsresol ); + } + + return retval; +} + +/* --------------------------------- BR/EDR ----------------------------- */ + +static PCAPNG_RESULT +create_bredr_capture_file_single_interface( PCAPNG_HANDLE * handle, + const char * filename, + const option_header * interface_options ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + + retval = pcapng_create( handle, + filename, + (const option_header *) &libbtbb_section_options, + (size_t) getpagesize( ), + DLT_BLUETOOTH_BREDR_BB, + BREDR_MAX_PAYLOAD, + interface_options, + (size_t) getpagesize( ) ); + + if (retval == PCAPNG_OK) { + /* if there is no timestamp resolution alread in the + interface options, record nanosecond resolution */ + retval = check_and_fix_tsresol( handle, interface_options ); + + if (retval != PCAPNG_OK) { + (void) pcapng_close( handle ); + } + } + + return retval; +} + +int btbb_pcapng_create_file( const char *filename, + const char *interface_desc, + btbb_pcapng_handle ** ph ) +{ + int retval = PCAPNG_OK; + PCAPNG_HANDLE * handle = malloc( sizeof(PCAPNG_HANDLE) ); + if (handle) { + const option_header * popt = NULL; + struct { + option_header header; + char desc[256]; + } ifopt = { + .header = { + .option_code = IF_DESCRIPTION, + } + }; + if (interface_desc) { + (void) strncpy( &ifopt.desc[0], interface_desc, 256 ); + ifopt.desc[255] = '\0'; + ifopt.header.option_length = strlen( ifopt.desc ); + popt = (const option_header *) &ifopt; + } + + retval = -create_bredr_capture_file_single_interface( handle, + filename, + popt ); + if (retval == PCAPNG_OK) { + *ph = (btbb_pcapng_handle *) handle; + } + else { + free( handle ); + } + } + else { + retval = -PCAPNG_NO_MEMORY; + } + return retval; +} + +static PCAPNG_RESULT +append_bredr_packet( PCAPNG_HANDLE * handle, + pcapng_bredr_packet * pkt ) +{ + return pcapng_append_packet( handle, ( const enhanced_packet_block *) pkt ); +} + +static void +assemble_pcapng_bredr_packet( pcapng_bredr_packet * pkt, + const uint32_t interface_id, + const uint64_t ns, + const uint32_t caplen, + const uint8_t rf_channel, + const int8_t signal_power, + const int8_t noise_power, + const uint8_t access_code_offenses, + const uint8_t payload_transport, + const uint8_t payload_rate, + const uint8_t corrected_header_bits, + const int16_t corrected_payload_bits, + const uint32_t lap, + const uint32_t ref_lap, + const uint8_t ref_uap, + const uint32_t bt_header, + const uint16_t flags, + const char * payload ) +{ + uint32_t pcapng_caplen = sizeof(pcap_bluetooth_bredr_bb_header)+caplen; + uint32_t block_length = 4*((36+pcapng_caplen+3)/4); + uint32_t reflapuap = (ref_lap&0xffffff) | (ref_uap<<24); + + pkt->blk_header.block_type = BLOCK_TYPE_ENHANCED_PACKET; + pkt->blk_header.block_total_length = block_length; + pkt->blk_header.interface_id = interface_id; + pkt->blk_header.timestamp_high = (uint32_t) (ns >> 32); + pkt->blk_header.timestamp_low = (uint32_t) (ns & 0x0ffffffffull); + pkt->blk_header.captured_len = pcapng_caplen; + pkt->blk_header.packet_len = pcapng_caplen; + pkt->bredr_bb_header.rf_channel = rf_channel; + pkt->bredr_bb_header.signal_power = signal_power; + pkt->bredr_bb_header.noise_power = noise_power; + pkt->bredr_bb_header.access_code_offenses = access_code_offenses; + pkt->bredr_bb_header.payload_transport_rate = + (payload_transport << 4) | payload_rate; + pkt->bredr_bb_header.corrected_header_bits = corrected_header_bits; + pkt->bredr_bb_header.corrected_payload_bits = htole16( corrected_payload_bits ); + pkt->bredr_bb_header.lap = htole32( lap ); + pkt->bredr_bb_header.ref_lap_uap = htole32( reflapuap ); + pkt->bredr_bb_header.bt_header = htole16( bt_header ); + pkt->bredr_bb_header.flags = htole16( flags ); + if (caplen) { + (void) memcpy( &pkt->bredr_payload[0], payload, caplen ); + } + else { + pkt->bredr_bb_header.flags &= htole16( ~BREDR_PAYLOAD_PRESENT ); + } + ((uint32_t *)pkt)[block_length/4-2] = 0x00000000; /* no-options */ + ((uint32_t *)pkt)[block_length/4-1] = block_length; +} + +int btbb_pcapng_append_packet(btbb_pcapng_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t reflap, const uint8_t refuap, + const btbb_packet *pkt) +{ + uint16_t flags = BREDR_DEWHITENED | BREDR_SIGPOWER_VALID | + ((noisedbm < sigdbm) ? BREDR_NOISEPOWER_VALID : 0) | + ((reflap != LAP_ANY) ? BREDR_REFLAP_VALID : 0) | + ((refuap != UAP_ANY) ? BREDR_REFUAP_VALID : 0); + int caplen = btbb_packet_get_payload_length(pkt); + char payload_bytes[caplen]; + btbb_get_payload_packed( pkt, &payload_bytes[0] ); + caplen = MIN(BREDR_MAX_PAYLOAD, caplen); + pcapng_bredr_packet pcapng_pkt; + assemble_pcapng_bredr_packet( &pcapng_pkt, + 0, + ns, + caplen, + btbb_packet_get_channel(pkt), + sigdbm, + noisedbm, + btbb_packet_get_ac_errors(pkt), + btbb_packet_get_transport(pkt), + btbb_packet_get_modulation(pkt), + 0, /* TODO: corrected header bits */ + 0, /* TODO: corrected payload bits */ + btbb_packet_get_lap(pkt), + reflap, + refuap, + btbb_packet_get_header_packed(pkt), + flags, + payload_bytes ); + return -append_bredr_packet( (PCAPNG_HANDLE *)h, &pcapng_pkt ); +} + +static PCAPNG_RESULT +record_bd_addr_info( PCAPNG_HANDLE * handle, + const uint64_t bd_addr, + const uint8_t uap_mask, + const uint8_t nap_valid ) +{ + const bredr_br_addr_option bdopt = { + .header = { + .option_code = PCAPNG_BREDR_OPTION_BD_ADDR, + .option_length = sizeof(bredr_br_addr_option), + }, + .bd_addr_info = { + .bd_addr = { + ((bd_addr>>0) & 0xff), + ((bd_addr>>8) & 0xff), + ((bd_addr>>16) & 0xff), + ((bd_addr>>24) & 0xff), + ((bd_addr>>32) & 0xff), + ((bd_addr>>40) & 0xff) + }, + .uap_mask = uap_mask, + .nap_valid = nap_valid, + } + }; + return pcapng_append_interface_option( handle, + (const option_header *) &bdopt ); +} + +int btbb_pcapng_record_bdaddr(btbb_pcapng_handle * h, const uint64_t bdaddr, + const uint8_t uapmask, const uint8_t napvalid) +{ + return -record_bd_addr_info( (PCAPNG_HANDLE *) h, + bdaddr, uapmask, napvalid ); +} + +static PCAPNG_RESULT +record_bredr_master_clock_info( PCAPNG_HANDLE * handle, + const uint64_t bd_addr, + const uint64_t ns, + const uint32_t clk, + const uint32_t clk_mask) +{ + const bredr_clk_option mcopt = { + .header = { + .option_code = PCAPNG_BREDR_OPTION_MASTER_CLOCK_INFO, + .option_length = sizeof(bredr_clk_option) + }, + .clock_info = { + .ts = ns, + .lap_uap = htole32(bd_addr & 0xffffffff), + .clk = clk, + .clk_mask = clk_mask + } + }; + return pcapng_append_interface_option( handle, + (const option_header *) &mcopt ); +} + +int btbb_pcapng_record_btclock(btbb_pcapng_handle * h, const uint64_t bdaddr, + const uint64_t ns, const uint32_t clk, + const uint32_t clkmask) +{ + return -record_bredr_master_clock_info( (PCAPNG_HANDLE *) h, + bdaddr, ns, clk, clkmask ); +} + +int btbb_pcapng_close(btbb_pcapng_handle * h) +{ + pcapng_close( (PCAPNG_HANDLE *) h ); + if (h) { + free( h ); + } + return -PCAPNG_INVALID_HANDLE; +} + +/* --------------------------------- Low Energy ---------------------------- */ + +static PCAPNG_RESULT +create_le_capture_file_single_interface( PCAPNG_HANDLE * handle, + const char * filename, + const option_header * interface_options ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + + retval = pcapng_create( handle, + filename, + (const option_header *) &libbtbb_section_options, + (size_t) getpagesize( ), + DLT_BLUETOOTH_LE_LL_WITH_PHDR, + 64, + interface_options, + (size_t) getpagesize( ) ); + + if (retval == PCAPNG_OK) { + /* if there is no timestamp resolution alread in the + interface options, record nanosecond resolution */ + retval = check_and_fix_tsresol( handle, interface_options ); + + if (retval != PCAPNG_OK) { + (void) pcapng_close( handle ); + } + } + + return retval; +} + +int +lell_pcapng_create_file(const char *filename, const char *interface_desc, + lell_pcapng_handle ** ph) +{ + int retval = PCAPNG_OK; + PCAPNG_HANDLE * handle = malloc( sizeof(PCAPNG_HANDLE) ); + if (handle) { + const option_header * popt = NULL; + struct { + option_header header; + char desc[256]; + } ifopt = { + .header = { + .option_code = IF_DESCRIPTION, + } + }; + if (interface_desc) { + (void) strncpy( &ifopt.desc[0], interface_desc, 256 ); + ifopt.desc[255] = '\0'; + ifopt.header.option_length = strlen( ifopt.desc ); + popt = (const option_header *) &ifopt; + } + + retval = -create_le_capture_file_single_interface( handle, + filename, + popt ); + if (retval == PCAPNG_OK) { + *ph = (lell_pcapng_handle *) handle; + } + else { + free( handle ); + } + } + else { + retval = -PCAPNG_NO_MEMORY; + } + return retval; +} + +static PCAPNG_RESULT +append_le_packet( PCAPNG_HANDLE * handle, + pcapng_le_packet * pkt ) +{ + return pcapng_append_packet( handle, ( const enhanced_packet_block *) pkt ); +} + +/* Size of a PCAPNG enhanced packet block with no packet data. + NOTE: The pcap_bluetooth_le_ll_header is part of the packet data of + the enhanced block. */ +#define PCAPNG_ENHANCED_BLK_SZ 36 + +static void +assemble_pcapng_le_packet( pcapng_le_packet * pkt, + const uint32_t interface_id, + const uint64_t ns, + const uint32_t caplen, + const uint8_t rf_channel, + const int8_t signal_power, + const int8_t noise_power, + const uint8_t access_address_offenses, + const uint32_t ref_access_address, + const uint16_t flags, + const uint8_t * lepkt ) +{ + uint32_t pcapng_caplen = sizeof(pcap_bluetooth_le_ll_header)+caplen; + uint32_t block_length = 4*((PCAPNG_ENHANCED_BLK_SZ+pcapng_caplen+3)/4); + + assert(caplen <= LE_MAX_PAYLOAD); + + pkt->blk_header.block_type = BLOCK_TYPE_ENHANCED_PACKET; + pkt->blk_header.block_total_length = block_length; + pkt->blk_header.interface_id = interface_id; + pkt->blk_header.timestamp_high = (uint32_t) (ns >> 32); + pkt->blk_header.timestamp_low = (uint32_t) (ns & 0x0ffffffffull); + pkt->blk_header.captured_len = pcapng_caplen; + pkt->blk_header.packet_len = pcapng_caplen; + pkt->le_ll_header.rf_channel = rf_channel; + pkt->le_ll_header.signal_power = signal_power; + pkt->le_ll_header.noise_power = noise_power; + pkt->le_ll_header.access_address_offenses = access_address_offenses; + pkt->le_ll_header.ref_access_address = htole32( ref_access_address ); + pkt->le_ll_header.flags = htole16( flags ); + (void) memcpy( &pkt->le_packet[0], lepkt, caplen ); + ((uint32_t *)pkt)[block_length/4-2] = 0x00000000; /* no-options */ + ((uint32_t *)pkt)[block_length/4-1] = block_length; +} + +int +lell_pcapng_append_packet(lell_pcapng_handle * h, const uint64_t ns, + const int8_t sigdbm, const int8_t noisedbm, + const uint32_t refAA, const lell_packet *pkt) +{ + uint16_t flags = LE_DEWHITENED | LE_AA_OFFENSES_VALID | + LE_SIGPOWER_VALID | + ((noisedbm < sigdbm) ? LE_NOISEPOWER_VALID : 0) | + (lell_packet_is_data(pkt) ? 0 : LE_REF_AA_VALID); + pcapng_le_packet pcapng_pkt; + + /* The extra 9 bytes added to the packet length are for: + 4 bytes for Access Address + 2 bytes for PDU header + 3 bytes for CRC */ + assemble_pcapng_le_packet( &pcapng_pkt, + 0, + ns, + 9+pkt->length, + pkt->channel_k, + sigdbm, + noisedbm, + pkt->access_address_offenses, + refAA, + flags, + &pkt->symbols[0] ); + int retval = -append_le_packet( (PCAPNG_HANDLE *) h, &pcapng_pkt ); + if ((retval == 0) && !lell_packet_is_data(pkt) && (pkt->adv_type == CONNECT_REQ)) { + (void) lell_pcapng_record_connect_req(h, ns, &pkt->symbols[0]); + } + return retval; +} + +static PCAPNG_RESULT +record_le_connect_req_info( PCAPNG_HANDLE * handle, + const uint64_t ns, + const uint8_t * pdu ) +{ + le_ll_connection_info_option cropt = { + .header = { + .option_code = PCAPNG_LE_LL_CONNECTION_INFO, + .option_length = sizeof(le_ll_connection_info_option) + }, + .connection_info = { + .ns = ns + } + }; + (void) memcpy( &cropt.connection_info.pdu.bytes[0], pdu, 34 ); + return pcapng_append_interface_option( handle, + (const option_header *) &cropt ); +} + +int +lell_pcapng_record_connect_req(lell_pcapng_handle * h, const uint64_t ns, + const uint8_t * pdu) +{ + return -record_le_connect_req_info( (PCAPNG_HANDLE *) h, ns, pdu ); +} + +int lell_pcapng_close(lell_pcapng_handle *h) +{ + pcapng_close( (PCAPNG_HANDLE *) h ); + if (h) { + free( h ); + } + return -PCAPNG_INVALID_HANDLE; +} diff --git a/libbtbb-2015-10-R1/lib/src/pcapng-bt.h b/libbtbb-2015-10-R1/lib/src/pcapng-bt.h new file mode 100644 index 0000000..3d13758 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/pcapng-bt.h @@ -0,0 +1,120 @@ +/* -*- c -*- */ +/* + * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef PCAPNG_BT_DOT_H +#define PCAPNG_BT_DOT_H + +#include "pcap-common.h" +#include "pcapng.h" + +typedef struct __attribute__((packed)) { + uint32_t centre_freq; + uint32_t analog_bandwidth; + int32_t intermediate_freq; + uint32_t sampling_bandwidth; +} bt_wideband_rf_info; + +typedef struct __attribute__((packed)) { + option_header header; + bt_wideband_rf_info wideband_rf_info; +} bt_wideband_rf_option; + +#define PCAPNG_BT_WIDEBAND_RF_INFO 0xd300 + +/* --------------------------------- BR/EDR ----------------------------- */ + +typedef struct __attribute__((packed)) { + enhanced_packet_block blk_header; + pcap_bluetooth_bredr_bb_header bredr_bb_header; + uint8_t bredr_payload[BREDR_MAX_PAYLOAD]; +} pcapng_bredr_packet; + +typedef struct __attribute__((packed)) { + uint8_t bd_addr[6]; + uint8_t uap_mask; + uint8_t nap_valid; +} bredr_bd_addr_info; + +typedef struct __attribute__((packed)) { + option_header header; + bredr_bd_addr_info bd_addr_info; +} bredr_br_addr_option; + +typedef struct __attribute__((packed)) { + uint64_t ts; + uint32_t lap_uap; + uint32_t clk; + uint32_t clk_mask; +} bredr_clk_info; + +typedef struct __attribute__((packed)) { + option_header header; + bredr_clk_info clock_info; +} bredr_clk_option; + +#define PCAPNG_BREDR_OPTION_BD_ADDR 0xd340 +#define PCAPNG_BREDR_OPTION_MASTER_CLOCK_INFO 0xd341 + +/* --------------------------------- Low Energy ---------------------------- */ + +typedef struct __attribute__((packed)) { + enhanced_packet_block blk_header; + pcap_bluetooth_le_ll_header le_ll_header; + uint8_t le_packet[LE_MAX_PAYLOAD]; + + /* Force 32 bit alignment for options and blk_tot_length. */ + uint8_t pad[2]; + + /* Add space for OPTIONS and BLOCK_TOTAL_LENGTH at end of + block. These won't be at this position in the structure unless + the LE PDU is the full 39 bytes. */ + uint32_t options; + uint32_t blk_tot_length; +} pcapng_le_packet; + +typedef struct __attribute__((packed)) { + uint64_t ns; + union { + struct { + uint8_t InitA[6]; + uint8_t AdvA[6]; + uint8_t AA[4]; + uint8_t CRCInit[3]; + uint8_t WinSize; + uint8_t WinOffset[2]; + uint8_t Interval[2]; + uint8_t Latency[2]; + uint8_t Timeout[2]; + uint8_t ChM[5]; + uint8_t HopSCA; + } fields; + uint8_t bytes[0]; + } pdu; +} le_ll_connection_info; + +typedef struct __attribute__((packed)) { + option_header header; + le_ll_connection_info connection_info; +} le_ll_connection_info_option; + +#define PCAPNG_LE_LL_CONNECTION_INFO 0xd380 + +#endif /* PCAPNG_BT_DOT_H */ diff --git a/libbtbb-2015-10-R1/lib/src/pcapng.c b/libbtbb-2015-10-R1/lib/src/pcapng.c new file mode 100644 index 0000000..dbe61d8 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/pcapng.c @@ -0,0 +1,323 @@ +/* -*- c -*- */ +/* + * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "pcapng.h" + +#include +#include +#include +#include +#include +#include +#include + +static option_header padopt = { + .option_code = 0xffff, +}; + +PCAPNG_RESULT pcapng_create( PCAPNG_HANDLE * handle, + const char * filename, + const option_header * section_options, + const size_t section_options_space, + const uint16_t link_type, + const uint32_t snaplen, + const option_header * interface_options, + const size_t interface_options_space ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + int PGSZ = getpagesize( ); + size_t zeroes = 0; + ssize_t result = -1; + + handle->section_header = NULL; + handle->interface_description = NULL; + handle->section_header_size = handle->next_section_option_offset = + handle->interface_description_size = + handle->next_interface_option_offset = 0; + + handle->fd = open( filename, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP ); + if (handle->fd == -1) { + switch( errno ) { + case EEXIST: + retval = PCAPNG_FILE_EXISTS; + break; + case EMFILE: + case ENFILE: + retval = PCAPNG_TOO_MANY_FILES_OPEN; + break; + case ENOMEM: + case ENOSPC: + retval = PCAPNG_NO_MEMORY; + break; + default: + retval = PCAPNG_FILE_NOT_ALLOWED; + } + } + + if (retval == PCAPNG_OK) { + /* section header */ + const section_header_block shb = { + .block_type = BLOCK_TYPE_SECTION_HEADER, + .block_total_length = 28, + .byte_order_magic = SECTION_HEADER_BYTE_ORDER_MAGIC, + .major_version = 1, + .minor_version = 0, + .section_length = (uint64_t) -1, + }; + handle->section_header_size = sizeof( shb ); + result = write( handle->fd, &shb, sizeof( shb ) ); + /* write initial section options */ + while ((result != -1) && + section_options && + section_options->option_code && + section_options->option_length) { + size_t paddedsz = 4*((section_options->option_length+3)/4); + zeroes = paddedsz - section_options->option_length; + result = write( handle->fd, section_options, 4+section_options->option_length ); + while ((zeroes > 0) && (result != -1)) { + result = write( handle->fd, "\0", 1 ); + zeroes--; + } + section_options = (const option_header *) &((uint8_t *)section_options)[4+paddedsz]; + handle->section_header_size += (4+paddedsz); + } + handle->next_section_option_offset = handle->section_header_size; + } + + if (result == -1) { + retval = PCAPNG_FILE_WRITE_ERROR; + } + else { + /* determine the size of section header with desired space */ + zeroes = (size_t) PGSZ*((handle->section_header_size + 4 + + section_options_space + PGSZ - 1)/PGSZ) - + handle->section_header_size; + handle->section_header_size += zeroes; + while ((zeroes > 0) && (result != -1)) { + result = write( handle->fd, "\0", 1 ); + zeroes--; + } + + /* mmap the section header */ + handle->section_header = mmap( NULL, handle->section_header_size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + handle->fd, 0 ); + } + + if (retval == PCAPNG_OK) { + if (result == -1) { + retval = PCAPNG_FILE_WRITE_ERROR; + } + else if (handle->section_header == MAP_FAILED) { + retval = PCAPNG_MMAP_FAILED; + } + else { + /* write the interface header */ + const interface_description_block idb = { + .block_type = BLOCK_TYPE_INTERFACE, + .block_total_length = 0, + .link_type = link_type, + .snaplen = snaplen + }; + handle->interface_description_size = sizeof( idb ); + result = write( handle->fd, &idb, sizeof( idb ) ); + + /* write interface options */ + while ((result != -1) && + interface_options && + interface_options->option_code && + interface_options->option_length) { + size_t paddedsz = 4*((interface_options->option_length+3)/4); + zeroes = paddedsz - interface_options->option_length; + result = write( handle->fd, interface_options, 4+interface_options->option_length ); + while ((zeroes > 0) && (result != -1)) { + result = write( handle->fd, "\0", 1 ); + zeroes--; + } + interface_options = (const option_header *) &((uint8_t *)interface_options)[4+paddedsz]; + handle->interface_description_size += (4+paddedsz); + } + handle->next_interface_option_offset = handle->interface_description_size; + } + } + + if (retval == PCAPNG_OK) { + if (result == -1) { + retval = PCAPNG_FILE_WRITE_ERROR; + } + else { + /* determine the size of interface description with desired space */ + zeroes = (size_t) PGSZ*((handle->interface_description_size + 4 + + interface_options_space + PGSZ - 1)/PGSZ) - + handle->interface_description_size; + handle->interface_description_size += zeroes; + while ((zeroes > 0) && (result != -1)) { + result = write( handle->fd, "\0", 1 ); + zeroes--; + } + + /* mmap the interface description */ + handle->interface_description = mmap( NULL, handle->interface_description_size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + handle->fd, + handle->section_header_size ); + } + } + + if (retval == PCAPNG_OK) { + if (result == -1) { + retval = PCAPNG_FILE_WRITE_ERROR; + } + else if (handle->interface_description == MAP_FAILED) { + retval = PCAPNG_MMAP_FAILED; + } + else { + uint8_t * dest = &((uint8_t *)handle->section_header)[handle->next_section_option_offset]; + padopt.option_length = handle->section_header_size - + handle->next_section_option_offset - 12; + + /* Add padding options, update the header sizes. */ + (void) memcpy( dest, &padopt, sizeof( padopt ) ); + handle->section_header->block_total_length = + (uint32_t) handle->section_header_size; + ((uint32_t*)handle->section_header)[handle->section_header_size/4-1] = + (uint32_t) handle->section_header_size; + + padopt.option_length = handle->interface_description_size - + handle->next_interface_option_offset - 12; + dest = &((uint8_t *)handle->interface_description)[handle->next_interface_option_offset]; + (void) memcpy( dest, &padopt, sizeof( padopt ) ); + handle->interface_description->block_total_length = + (uint32_t) handle->interface_description_size; + ((uint32_t*)handle->interface_description)[handle->interface_description_size/4-1] = + (uint32_t) handle->interface_description_size; + + handle->section_header->section_length = (uint64_t) handle->interface_description_size; + } + } + + if (retval != PCAPNG_OK) { + (void) pcapng_close( handle ); + } + + return retval; +} + +PCAPNG_RESULT pcapng_append_section_option( PCAPNG_HANDLE * handle, + const option_header * section_option ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + if (handle && (handle->fd != -1)) { + if (handle->section_header && + (handle->section_header != MAP_FAILED) && + handle->next_section_option_offset && + section_option) { + size_t copysz = 4+section_option->option_length; + uint8_t * dest = &((uint8_t *)handle->section_header)[handle->next_section_option_offset]; + (void) memcpy( dest, section_option, copysz ); + handle->next_section_option_offset += 4*((copysz+3)/4); + + /* update padding option */ + dest = &((uint8_t *)handle->section_header)[handle->next_section_option_offset]; + padopt.option_length = handle->section_header_size - + handle->next_section_option_offset - 12; + (void) memcpy( dest, &padopt, sizeof( padopt ) ); + } + else { + retval = PCAPNG_NO_MEMORY; + } + } + else { + retval = PCAPNG_INVALID_HANDLE; + } + return retval; +} + +PCAPNG_RESULT pcapng_append_interface_option( PCAPNG_HANDLE * handle, + const option_header * interface_option ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + if (handle && (handle->fd != -1)) { + if (handle->interface_description && + (handle->interface_description != MAP_FAILED) && + handle->next_interface_option_offset && + interface_option) { + size_t copysz = 4+interface_option->option_length; + uint8_t * dest = &((uint8_t *)handle->interface_description)[handle->next_interface_option_offset]; + (void) memcpy( dest, interface_option, copysz ); + handle->next_interface_option_offset += 4*((copysz+3)/4); + + /* update padding option */ + dest = &((uint8_t *)handle->interface_description)[handle->next_interface_option_offset]; + padopt.option_length = handle->interface_description_size - + handle->next_interface_option_offset - 12; + (void) memcpy( dest, &padopt, sizeof( padopt ) ); + } + else { + retval = PCAPNG_NO_MEMORY; + } + } + else { + retval = PCAPNG_INVALID_HANDLE; + } + return retval; +} + +PCAPNG_RESULT pcapng_append_packet( PCAPNG_HANDLE * handle, + const enhanced_packet_block * packet ) +{ + PCAPNG_RESULT retval = PCAPNG_OK; + if (handle && (handle->fd != -1)) { + size_t writesz = packet->block_total_length; + ssize_t result = write( handle->fd, packet, writesz ); + if (result == -1) { + result = PCAPNG_FILE_WRITE_ERROR; + } + else { + handle->section_header->section_length += writesz; + } + } + else { + retval = PCAPNG_INVALID_HANDLE; + } + return retval; +} + +PCAPNG_RESULT pcapng_close( PCAPNG_HANDLE * handle ) +{ + if (handle->interface_description && + (handle->interface_description != MAP_FAILED)) { + (void) munmap( handle->interface_description, + handle->interface_description_size ); + } + if (handle->section_header && + (handle->section_header != MAP_FAILED)) { + (void) munmap( handle->section_header, + handle->section_header_size ); + } + if (handle->fd != -1) { + (void) close( handle->fd ); + } + return PCAPNG_OK; +} diff --git a/libbtbb-2015-10-R1/lib/src/pcapng.h b/libbtbb-2015-10-R1/lib/src/pcapng.h new file mode 100644 index 0000000..da2caf4 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/pcapng.h @@ -0,0 +1,198 @@ +/* -*- c -*- */ +/* + * Copyright 2014 Christopher D. Kilgour techie AT whiterocker.com + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef PCAPNG_DOT_H +#define PCAPNG_DOT_H + +#include +#include + +typedef struct __attribute__((packed)) { + uint16_t option_code; + uint16_t option_length; + uint32_t option_value[0]; +} option_header; + +#define OPT_ENDOFOPT 0 +#define OPT_COMMENT 1 + +typedef struct __attribute__((packed)) { + uint32_t block_type; + uint32_t block_total_length; + uint32_t byte_order_magic; + uint16_t major_version; + uint16_t minor_version; + uint64_t section_length; + option_header options[0]; +} section_header_block; + +#define SECTION_HEADER_BYTE_ORDER_MAGIC 0x1a2b3c4d + +#define SHB_HARDWARE 2 +#define SHB_OS 3 +#define SHB_USERAPPL 4 + +typedef struct __attribute__((packed)) { + uint32_t block_type; + uint32_t block_total_length; + uint16_t link_type; + uint16_t reserved; + uint32_t snaplen; + option_header options[0]; +} interface_description_block; + +#define IF_NAME 2 +#define IF_DESCRIPTION 3 +#define IF_IPV4ADDR 4 +#define IF_IPV6ADDR 5 +#define IF_MACADDR 6 +#define IF_EUIADDR 7 +#define IF_SPEED 8 +#define IF_TSRESOL 9 +#define IF_TZONE 10 +#define IF_FILTER 11 +#define IF_OS 12 +#define IF_FCSLEN 13 +#define IF_TSOFFSET 14 + +typedef struct __attribute__((packed)) { + uint32_t block_type; + uint32_t block_total_length; + uint32_t interface_id; + uint32_t timestamp_high; + uint32_t timestamp_low; + uint32_t captured_len; + uint32_t packet_len; + uint32_t packet_data[0]; +} enhanced_packet_block; + +#define EPB_FLAGS 2 +#define EPB_HASH 3 +#define EPB_DROPCOUNT 4 + +typedef struct __attribute__((packed)) { + uint32_t block_type; + uint32_t block_total_length; + uint32_t packet_len; + uint32_t packet_data[0]; +} simple_packet_block; + +typedef struct __attribute__((packed)) { + uint32_t block_type; + uint32_t block_total_length; + uint16_t record_type; + uint16_t record_length; + uint32_t record_value[0]; +} name_resolution_block; + +#define NRES_ENDOFRECORD 0 +#define NRES_IP4RECORD 1 +#define NRES_IP6RECORD 2 + +#define NS_DNSNAME 2 +#define NS_DNSIP4ADDR 3 +#define NS_DNSIP6ADDR 4 + +typedef struct __attribute__((packed)) { + uint32_t block_type; + uint32_t block_total_length; + uint32_t interface_id; + uint32_t timestamp_high; + uint32_t timestamp_low; + option_header options[0]; +} interface_statistics_block; + +#define ISB_STARTTIME 2 +#define ISB_ENDTIME 3 +#define ISB_IFRECV 4 +#define ISB_IFDROP 5 +#define ISB_FILTERACCEPT 6 +#define ISB_OSDROP 7 +#define ISB_USRDELIV 8 + +#define BLOCK_TYPE_INTERFACE 0x00000001 +#define BLOCK_TYPE_SIMPLE_PACKET 0x00000003 +#define BLOCK_TYPE_NAME_RESOLUTION 0x00000004 +#define BLOCK_TYPE_INTERFACE_STATISTICS 0x00000005 +#define BLOCK_TYPE_ENHANCED_PACKET 0x00000006 +#define BLOCK_TYPE_SECTION_HEADER 0x0a0d0d0a + +typedef struct { + int fd; + section_header_block * section_header; + size_t section_header_size; + size_t next_section_option_offset; + interface_description_block * interface_description; + size_t interface_description_size; + size_t next_interface_option_offset; +} PCAPNG_HANDLE; + +typedef enum { + PCAPNG_OK = 0, + PCAPNG_INVALID_HANDLE, + PCAPNG_FILE_NOT_ALLOWED, + PCAPNG_FILE_EXISTS, + PCAPNG_TOO_MANY_FILES_OPEN, + PCAPNG_NO_MEMORY, + PCAPNG_FILE_WRITE_ERROR, + PCAPNG_MMAP_FAILED, +} PCAPNG_RESULT; + +/** + * Create a new PCAP-NG file and set aside space in the section and + * interface headers for options to be recorded/added while packets + * are captured. + * + * @param handle pointer to a handle that is populated by this call + * @param filename file to create + * @param section_options list of initial section options, can be NULL + * @param section_options_space size in bytes dedicated to storing extra section + * options; will be rounded up so section header + * is an integer number of memory pages + * @param link_type + * @param snaplen + * @param interface_options list of initial interface options, can be NULL + * @param interface_options_space size in bytes dedicated to storing extra interface + * options; will be rounded up so interface header + * is an integer number of memory pages + * @returns 0 on success, non zero result code otherwisex + */ +PCAPNG_RESULT pcapng_create( PCAPNG_HANDLE * handle, + const char * filename, + const option_header * section_options, + const size_t section_options_space, + const uint16_t link_type, + const uint32_t snaplen, + const option_header * interface_options, + const size_t interface_options_space ); + +PCAPNG_RESULT pcapng_append_section_option( PCAPNG_HANDLE * handle, + const option_header * section_option ); + +PCAPNG_RESULT pcapng_append_interface_option( PCAPNG_HANDLE * handle, + const option_header * interface_option ); + +PCAPNG_RESULT pcapng_append_packet( PCAPNG_HANDLE * handle, + const enhanced_packet_block * packet ); + +PCAPNG_RESULT pcapng_close( PCAPNG_HANDLE * handle ); + +#endif /* PCAPNG_DOT_H */ diff --git a/libbtbb-2015-10-R1/lib/src/sw_check_tables.h b/libbtbb-2015-10-R1/lib/src/sw_check_tables.h new file mode 100644 index 0000000..62874b2 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/sw_check_tables.h @@ -0,0 +1,4 @@ +static const uint64_t sw_check_table4[] = {0x000000000ULL, 0x100000000ULL, 0x200000000ULL, 0x300000000ULL, 0x185713da9ULL, 0x085713da9ULL, 0x385713da9ULL, 0x285713da9ULL, 0x30ae27b52ULL, 0x20ae27b52ULL, 0x10ae27b52ULL, 0x00ae27b52ULL, 0x28f9346fbULL, 0x38f9346fbULL, 0x08f9346fbULL, 0x18f9346fbULL, 0x390b5cb0dULL, 0x290b5cb0dULL, 0x190b5cb0dULL, 0x090b5cb0dULL, 0x215c4f6a4ULL, 0x315c4f6a4ULL, 0x015c4f6a4ULL, 0x115c4f6a4ULL, 0x09a57b05fULL, 0x19a57b05fULL, 0x29a57b05fULL, 0x39a57b05fULL, 0x11f268df6ULL, 0x01f268df6ULL, 0x31f268df6ULL, 0x21f268df6ULL, 0x2a41aabb3ULL, 0x3a41aabb3ULL, 0x0a41aabb3ULL, 0x1a41aabb3ULL, 0x3216b961aULL, 0x2216b961aULL, 0x1216b961aULL, 0x0216b961aULL, 0x1aef8d0e1ULL, 0x0aef8d0e1ULL, 0x3aef8d0e1ULL, 0x2aef8d0e1ULL, 0x02b89ed48ULL, 0x12b89ed48ULL, 0x22b89ed48ULL, 0x32b89ed48ULL, 0x134af60beULL, 0x034af60beULL, 0x334af60beULL, 0x234af60beULL, 0x0b1de5d17ULL, 0x1b1de5d17ULL, 0x2b1de5d17ULL, 0x3b1de5d17ULL, 0x23e4d1becULL, 0x33e4d1becULL, 0x03e4d1becULL, 0x13e4d1becULL, 0x3bb3c2645ULL, 0x2bb3c2645ULL, 0x1bb3c2645ULL, 0x0bb3c2645ULL, 0x0cd446acfULL, 0x1cd446acfULL, 0x2cd446acfULL, 0x3cd446acfULL, 0x148355766ULL, 0x048355766ULL, 0x348355766ULL, 0x248355766ULL, 0x3c7a6119dULL, 0x2c7a6119dULL, 0x1c7a6119dULL, 0x0c7a6119dULL, 0x242d72c34ULL, 0x342d72c34ULL, 0x042d72c34ULL, 0x142d72c34ULL, 0x35df1a1c2ULL, 0x25df1a1c2ULL, 0x15df1a1c2ULL, 0x05df1a1c2ULL, 0x2d8809c6bULL, 0x3d8809c6bULL, 0x0d8809c6bULL, 0x1d8809c6bULL, 0x05713da90ULL, 0x15713da90ULL, 0x25713da90ULL, 0x35713da90ULL, 0x1d262e739ULL, 0x0d262e739ULL, 0x3d262e739ULL, 0x2d262e739ULL, 0x2695ec17cULL, 0x3695ec17cULL, 0x0695ec17cULL, 0x1695ec17cULL, 0x3ec2ffcd5ULL, 0x2ec2ffcd5ULL, 0x1ec2ffcd5ULL, 0x0ec2ffcd5ULL, 0x163bcba2eULL, 0x063bcba2eULL, 0x363bcba2eULL, 0x263bcba2eULL, 0x0e6cd8787ULL, 0x1e6cd8787ULL, 0x2e6cd8787ULL, 0x3e6cd8787ULL, 0x1f9eb0a71ULL, 0x0f9eb0a71ULL, 0x3f9eb0a71ULL, 0x2f9eb0a71ULL, 0x07c9a37d8ULL, 0x17c9a37d8ULL, 0x27c9a37d8ULL, 0x37c9a37d8ULL, 0x2f3097123ULL, 0x3f3097123ULL, 0x0f3097123ULL, 0x1f3097123ULL, 0x376784c8aULL, 0x276784c8aULL, 0x176784c8aULL, 0x076784c8aULL, 0x19a88d59eULL, 0x09a88d59eULL, 0x39a88d59eULL, 0x29a88d59eULL, 0x01ff9e837ULL, 0x11ff9e837ULL, 0x21ff9e837ULL, 0x31ff9e837ULL, 0x2906aaeccULL, 0x3906aaeccULL, 0x0906aaeccULL, 0x1906aaeccULL, 0x3151b9365ULL, 0x2151b9365ULL, 0x1151b9365ULL, 0x0151b9365ULL, 0x20a3d1e93ULL, 0x30a3d1e93ULL, 0x00a3d1e93ULL, 0x10a3d1e93ULL, 0x38f4c233aULL, 0x28f4c233aULL, 0x18f4c233aULL, 0x08f4c233aULL, 0x100df65c1ULL, 0x000df65c1ULL, 0x300df65c1ULL, 0x200df65c1ULL, 0x085ae5868ULL, 0x185ae5868ULL, 0x285ae5868ULL, 0x385ae5868ULL, 0x33e927e2dULL, 0x23e927e2dULL, 0x13e927e2dULL, 0x03e927e2dULL, 0x2bbe34384ULL, 0x3bbe34384ULL, 0x0bbe34384ULL, 0x1bbe34384ULL, 0x03470057fULL, 0x13470057fULL, 0x23470057fULL, 0x33470057fULL, 0x1b10138d6ULL, 0x0b10138d6ULL, 0x3b10138d6ULL, 0x2b10138d6ULL, 0x0ae27b520ULL, 0x1ae27b520ULL, 0x2ae27b520ULL, 0x3ae27b520ULL, 0x12b568889ULL, 0x02b568889ULL, 0x32b568889ULL, 0x22b568889ULL, 0x3a4c5ce72ULL, 0x2a4c5ce72ULL, 0x1a4c5ce72ULL, 0x0a4c5ce72ULL, 0x221b4f3dbULL, 0x321b4f3dbULL, 0x021b4f3dbULL, 0x121b4f3dbULL, 0x157ccbf51ULL, 0x057ccbf51ULL, 0x357ccbf51ULL, 0x257ccbf51ULL, 0x0d2bd82f8ULL, 0x1d2bd82f8ULL, 0x2d2bd82f8ULL, 0x3d2bd82f8ULL, 0x25d2ec403ULL, 0x35d2ec403ULL, 0x05d2ec403ULL, 0x15d2ec403ULL, 0x3d85ff9aaULL, 0x2d85ff9aaULL, 0x1d85ff9aaULL, 0x0d85ff9aaULL, 0x2c779745cULL, 0x3c779745cULL, 0x0c779745cULL, 0x1c779745cULL, 0x3420849f5ULL, 0x2420849f5ULL, 0x1420849f5ULL, 0x0420849f5ULL, 0x1cd9b0f0eULL, 0x0cd9b0f0eULL, 0x3cd9b0f0eULL, 0x2cd9b0f0eULL, 0x048ea32a7ULL, 0x148ea32a7ULL, 0x248ea32a7ULL, 0x348ea32a7ULL, 0x3f3d614e2ULL, 0x2f3d614e2ULL, 0x1f3d614e2ULL, 0x0f3d614e2ULL, 0x276a7294bULL, 0x376a7294bULL, 0x076a7294bULL, 0x176a7294bULL, 0x0f9346fb0ULL, 0x1f9346fb0ULL, 0x2f9346fb0ULL, 0x3f9346fb0ULL, 0x17c455219ULL, 0x07c455219ULL, 0x37c455219ULL, 0x27c455219ULL, 0x06363dfefULL, 0x16363dfefULL, 0x26363dfefULL, 0x36363dfefULL, 0x1e612e246ULL, 0x0e612e246ULL, 0x3e612e246ULL, 0x2e612e246ULL, 0x36981a4bdULL, 0x26981a4bdULL, 0x16981a4bdULL, 0x06981a4bdULL, 0x2ecf09914ULL, 0x3ecf09914ULL, 0x0ecf09914ULL, 0x1ecf09914ULL}; +static const uint64_t sw_check_table5[] = {0x000000000ULL, 0x33511ab3cULL, 0x3ef526bd1ULL, 0x0da43c0edULL, 0x25bd5ea0bULL, 0x16ec44137ULL, 0x1b48781daULL, 0x281962ae6ULL, 0x132dae9bfULL, 0x207cb4283ULL, 0x2dd88826eULL, 0x1e8992952ULL, 0x3690f03b4ULL, 0x05c1ea888ULL, 0x0865d6865ULL, 0x3b34cc359ULL, 0x265b5d37eULL, 0x150a47842ULL, 0x18ae7b8afULL, 0x2bff61393ULL, 0x03e603975ULL, 0x30b719249ULL, 0x3d13252a4ULL, 0x0e423f998ULL, 0x3576f3ac1ULL, 0x0627e91fdULL, 0x0b83d5110ULL, 0x38d2cfa2cULL, 0x10cbad0caULL, 0x239ab7bf6ULL, 0x2e3e8bb1bULL, 0x1d6f91027ULL, 0x14e1a9b55ULL, 0x27b0b3069ULL, 0x2a148f084ULL, 0x194595bb8ULL, 0x315cf715eULL, 0x020deda62ULL, 0x0fa9d1a8fULL, 0x3cf8cb1b3ULL, 0x07cc072eaULL, 0x349d1d9d6ULL, 0x39392193bULL, 0x0a683b207ULL, 0x2271598e1ULL, 0x1120433ddULL, 0x1c847f330ULL, 0x2fd56580cULL, 0x32baf482bULL, 0x01ebee317ULL, 0x0c4fd23faULL, 0x3f1ec88c6ULL, 0x1707aa220ULL, 0x2456b091cULL, 0x29f28c9f1ULL, 0x1aa3962cdULL, 0x21975a194ULL, 0x12c640aa8ULL, 0x1f627ca45ULL, 0x2c3366179ULL, 0x042a04b9fULL, 0x377b1e0a3ULL, 0x3adf2204eULL, 0x098e38b72ULL, 0x29c3536aaULL, 0x1a9249d96ULL, 0x173675d7bULL, 0x24676f647ULL, 0x0c7e0dca1ULL, 0x3f2f1779dULL, 0x328b2b770ULL, 0x01da31c4cULL, 0x3aeefdf15ULL, 0x09bfe7429ULL, 0x041bdb4c4ULL, 0x374ac1ff8ULL, 0x1f53a351eULL, 0x2c02b9e22ULL, 0x21a685ecfULL, 0x12f79f5f3ULL, 0x0f980e5d4ULL, 0x3cc914ee8ULL, 0x316d28e05ULL, 0x023c32539ULL, 0x2a2550fdfULL, 0x19744a4e3ULL, 0x14d07640eULL, 0x27816cf32ULL, 0x1cb5a0c6bULL, 0x2fe4ba757ULL, 0x2240867baULL, 0x11119cc86ULL, 0x3908fe660ULL, 0x0a59e4d5cULL, 0x07fdd8db1ULL, 0x34acc268dULL, 0x3d22fadffULL, 0x0e73e06c3ULL, 0x03d7dc62eULL, 0x3086c6d12ULL, 0x189fa47f4ULL, 0x2bcebecc8ULL, 0x266a82c25ULL, 0x153b98719ULL, 0x2e0f54440ULL, 0x1d5e4ef7cULL, 0x10fa72f91ULL, 0x23ab684adULL, 0x0bb20ae4bULL, 0x38e310577ULL, 0x35472c59aULL, 0x061636ea6ULL, 0x1b79a7e81ULL, 0x2828bd5bdULL, 0x258c81550ULL, 0x16dd9be6cULL, 0x3ec4f948aULL, 0x0d95e3fb6ULL, 0x0031dff5bULL, 0x3360c5467ULL, 0x08540973eULL, 0x3b0513c02ULL, 0x36a12fcefULL, 0x05f0357d3ULL, 0x2de957d35ULL, 0x1eb84d609ULL, 0x131c716e4ULL, 0x204d6bdd8ULL, 0x0bd1b50fdULL, 0x3880afbc1ULL, 0x352493b2cULL, 0x067589010ULL, 0x2e6cebaf6ULL, 0x1d3df11caULL, 0x1099cd127ULL, 0x23c8d7a1bULL, 0x18fc1b942ULL, 0x2bad0127eULL, 0x26093d293ULL, 0x1558279afULL, 0x3d4145349ULL, 0x0e105f875ULL, 0x03b463898ULL, 0x30e5793a4ULL, 0x2d8ae8383ULL, 0x1edbf28bfULL, 0x137fce852ULL, 0x202ed436eULL, 0x0837b6988ULL, 0x3b66ac2b4ULL, 0x36c290259ULL, 0x05938a965ULL, 0x3ea746a3cULL, 0x0df65c100ULL, 0x0052601edULL, 0x33037aad1ULL, 0x1b1a18037ULL, 0x284b02b0bULL, 0x25ef3ebe6ULL, 0x16be240daULL, 0x1f301cba8ULL, 0x2c6106094ULL, 0x21c53a079ULL, 0x129420b45ULL, 0x3a8d421a3ULL, 0x09dc58a9fULL, 0x047864a72ULL, 0x37297e14eULL, 0x0c1db2217ULL, 0x3f4ca892bULL, 0x32e8949c6ULL, 0x01b98e2faULL, 0x29a0ec81cULL, 0x1af1f6320ULL, 0x1755ca3cdULL, 0x2404d08f1ULL, 0x396b418d6ULL, 0x0a3a5b3eaULL, 0x079e67307ULL, 0x34cf7d83bULL, 0x1cd61f2ddULL, 0x2f87059e1ULL, 0x22233990cULL, 0x117223230ULL, 0x2a46ef169ULL, 0x1917f5a55ULL, 0x14b3c9ab8ULL, 0x27e2d3184ULL, 0x0ffbb1b62ULL, 0x3caaab05eULL, 0x310e970b3ULL, 0x025f8db8fULL, 0x2212e6657ULL, 0x1143fcd6bULL, 0x1ce7c0d86ULL, 0x2fb6da6baULL, 0x07afb8c5cULL, 0x34fea2760ULL, 0x395a9e78dULL, 0x0a0b84cb1ULL, 0x313f48fe8ULL, 0x026e524d4ULL, 0x0fca6e439ULL, 0x3c9b74f05ULL, 0x1482165e3ULL, 0x27d30cedfULL, 0x2a7730e32ULL, 0x19262a50eULL, 0x0449bb529ULL, 0x3718a1e15ULL, 0x3abc9def8ULL, 0x09ed875c4ULL, 0x21f4e5f22ULL, 0x12a5ff41eULL, 0x1f01c34f3ULL, 0x2c50d9fcfULL, 0x176415c96ULL, 0x24350f7aaULL, 0x299133747ULL, 0x1ac029c7bULL, 0x32d94b69dULL, 0x018851da1ULL, 0x0c2c6dd4cULL, 0x3f7d77670ULL, 0x36f34fd02ULL, 0x05a25563eULL, 0x0806696d3ULL, 0x3b5773defULL, 0x134e11709ULL, 0x201f0bc35ULL, 0x2dbb37cd8ULL, 0x1eea2d7e4ULL, 0x25dee14bdULL, 0x168ffbf81ULL, 0x1b2bc7f6cULL, 0x287add450ULL, 0x0063bfeb6ULL, 0x3332a558aULL, 0x3e9699567ULL, 0x0dc783e5bULL, 0x10a812e7cULL, 0x23f908540ULL, 0x2e5d345adULL, 0x1d0c2ee91ULL, 0x35154c477ULL, 0x064456f4bULL, 0x0be06afa6ULL, 0x38b17049aULL, 0x0385bc7c3ULL, 0x30d4a6cffULL, 0x3d709ac12ULL, 0x0e218072eULL, 0x2638e2dc8ULL, 0x1569f86f4ULL, 0x18cdc4619ULL, 0x2b9cded25ULL}; +static const uint64_t sw_check_table6[] = {0x000000000ULL, 0x17a36a1faULL, 0x2f46d43f4ULL, 0x38e5be20eULL, 0x06dabba41ULL, 0x1179d1bbbULL, 0x299c6f9b5ULL, 0x3e3f0584fULL, 0x0db577482ULL, 0x1a161d578ULL, 0x22f3a3776ULL, 0x3550c968cULL, 0x0b6fccec3ULL, 0x1ccca6f39ULL, 0x242918d37ULL, 0x338a72ccdULL, 0x1b6aee904ULL, 0x0cc9848feULL, 0x342c3aaf0ULL, 0x238f50b0aULL, 0x1db055345ULL, 0x0a133f2bfULL, 0x32f6810b1ULL, 0x2555eb14bULL, 0x16df99d86ULL, 0x017cf3c7cULL, 0x39994de72ULL, 0x2e3a27f88ULL, 0x1005227c7ULL, 0x07a64863dULL, 0x3f43f6433ULL, 0x28e09c5c9ULL, 0x36d5dd208ULL, 0x2176b73f2ULL, 0x1993091fcULL, 0x0e3063006ULL, 0x300f66849ULL, 0x27ac0c9b3ULL, 0x1f49b2bbdULL, 0x08ead8a47ULL, 0x3b60aa68aULL, 0x2cc3c0770ULL, 0x14267e57eULL, 0x038514484ULL, 0x3dba11ccbULL, 0x2a197bd31ULL, 0x12fcc5f3fULL, 0x055fafec5ULL, 0x2dbf33b0cULL, 0x3a1c59af6ULL, 0x02f9e78f8ULL, 0x155a8d902ULL, 0x2b658814dULL, 0x3cc6e20b7ULL, 0x04235c2b9ULL, 0x138036343ULL, 0x200a44f8eULL, 0x37a92ee74ULL, 0x0f4c90c7aULL, 0x18effad80ULL, 0x26d0ff5cfULL, 0x317395435ULL, 0x09962b63bULL, 0x1e35417c1ULL, 0x35fca99b9ULL, 0x225fc3843ULL, 0x1aba7da4dULL, 0x0d1917bb7ULL, 0x3326123f8ULL, 0x248578202ULL, 0x1c60c600cULL, 0x0bc3ac1f6ULL, 0x3849ded3bULL, 0x2feab4cc1ULL, 0x170f0aecfULL, 0x00ac60f35ULL, 0x3e936577aULL, 0x29300f680ULL, 0x11d5b148eULL, 0x0676db574ULL, 0x2e96470bdULL, 0x39352d147ULL, 0x01d093349ULL, 0x1673f92b3ULL, 0x284cfcafcULL, 0x3fef96b06ULL, 0x070a28908ULL, 0x10a9428f2ULL, 0x23233043fULL, 0x34805a5c5ULL, 0x0c65e47cbULL, 0x1bc68e631ULL, 0x25f98be7eULL, 0x325ae1f84ULL, 0x0abf5fd8aULL, 0x1d1c35c70ULL, 0x032974bb1ULL, 0x148a1ea4bULL, 0x2c6fa0845ULL, 0x3bccca9bfULL, 0x05f3cf1f0ULL, 0x1250a500aULL, 0x2ab51b204ULL, 0x3d16713feULL, 0x0e9c03f33ULL, 0x193f69ec9ULL, 0x21dad7cc7ULL, 0x3679bdd3dULL, 0x0846b8572ULL, 0x1fe5d2488ULL, 0x27006c686ULL, 0x30a30677cULL, 0x18439a2b5ULL, 0x0fe0f034fULL, 0x37054e141ULL, 0x20a6240bbULL, 0x1e99218f4ULL, 0x093a4b90eULL, 0x31dff5b00ULL, 0x267c9fafaULL, 0x15f6ed637ULL, 0x0255877cdULL, 0x3ab0395c3ULL, 0x2d1353439ULL, 0x132c56c76ULL, 0x048f3cd8cULL, 0x3c6a82f82ULL, 0x2bc9e8e78ULL, 0x33ae40edbULL, 0x240d2af21ULL, 0x1ce894d2fULL, 0x0b4bfecd5ULL, 0x3574fb49aULL, 0x22d791560ULL, 0x1a322f76eULL, 0x0d9145694ULL, 0x3e1b37a59ULL, 0x29b85dba3ULL, 0x115de39adULL, 0x06fe89857ULL, 0x38c18c018ULL, 0x2f62e61e2ULL, 0x1787583ecULL, 0x002432216ULL, 0x28c4ae7dfULL, 0x3f67c4625ULL, 0x07827a42bULL, 0x1021105d1ULL, 0x2e1e15d9eULL, 0x39bd7fc64ULL, 0x0158c1e6aULL, 0x16fbabf90ULL, 0x2571d935dULL, 0x32d2b32a7ULL, 0x0a370d0a9ULL, 0x1d9467153ULL, 0x23ab6291cULL, 0x3408088e6ULL, 0x0cedb6ae8ULL, 0x1b4edcb12ULL, 0x057b9dcd3ULL, 0x12d8f7d29ULL, 0x2a3d49f27ULL, 0x3d9e23eddULL, 0x03a126692ULL, 0x14024c768ULL, 0x2ce7f2566ULL, 0x3b449849cULL, 0x08ceea851ULL, 0x1f6d809abULL, 0x27883eba5ULL, 0x302b54a5fULL, 0x0e1451210ULL, 0x19b73b3eaULL, 0x2152851e4ULL, 0x36f1ef01eULL, 0x1e11735d7ULL, 0x09b21942dULL, 0x3157a7623ULL, 0x26f4cd7d9ULL, 0x18cbc8f96ULL, 0x0f68a2e6cULL, 0x378d1cc62ULL, 0x202e76d98ULL, 0x13a404155ULL, 0x04076e0afULL, 0x3ce2d02a1ULL, 0x2b41ba35bULL, 0x157ebfb14ULL, 0x02ddd5aeeULL, 0x3a386b8e0ULL, 0x2d9b0191aULL, 0x0652e9762ULL, 0x11f183698ULL, 0x29143d496ULL, 0x3eb75756cULL, 0x008852d23ULL, 0x172b38cd9ULL, 0x2fce86ed7ULL, 0x386decf2dULL, 0x0be79e3e0ULL, 0x1c44f421aULL, 0x24a14a014ULL, 0x3302201eeULL, 0x0d3d259a1ULL, 0x1a9e4f85bULL, 0x227bf1a55ULL, 0x35d89bbafULL, 0x1d3807e66ULL, 0x0a9b6df9cULL, 0x327ed3d92ULL, 0x25ddb9c68ULL, 0x1be2bc427ULL, 0x0c41d65ddULL, 0x34a4687d3ULL, 0x230702629ULL, 0x108d70ae4ULL, 0x072e1ab1eULL, 0x3fcba4910ULL, 0x2868ce8eaULL, 0x1657cb0a5ULL, 0x01f4a115fULL, 0x39111f351ULL, 0x2eb2752abULL, 0x30873456aULL, 0x27245e490ULL, 0x1fc1e069eULL, 0x08628a764ULL, 0x365d8ff2bULL, 0x21fee5ed1ULL, 0x191b5bcdfULL, 0x0eb831d25ULL, 0x3d32431e8ULL, 0x2a9129012ULL, 0x12749721cULL, 0x05d7fd3e6ULL, 0x3be8f8ba9ULL, 0x2c4b92a53ULL, 0x14ae2c85dULL, 0x030d469a7ULL, 0x2beddac6eULL, 0x3c4eb0d94ULL, 0x04ab0ef9aULL, 0x130864e60ULL, 0x2d376162fULL, 0x3a940b7d5ULL, 0x0271b55dbULL, 0x15d2df421ULL, 0x2658ad8ecULL, 0x31fbc7916ULL, 0x091e79b18ULL, 0x1ebd13ae2ULL, 0x2082162adULL, 0x37217c357ULL, 0x0fc4c2159ULL, 0x1867a80a3ULL}; +static const uint64_t sw_check_table7[] = {0x000000000ULL, 0x3f0b9201fULL, 0x264037d97ULL, 0x194ba5d88ULL, 0x14d77c687ULL, 0x2bdcee698ULL, 0x32974bb10ULL, 0x0d9cd9b0fULL, 0x29aef8d0eULL, 0x16a56ad11ULL, 0x0feecf099ULL, 0x30e55d086ULL, 0x3d7984b89ULL, 0x027216b96ULL, 0x1b39b361eULL, 0x243221601ULL, 0x0b0ae27b5ULL, 0x3401707aaULL, 0x2d4ad5a22ULL, 0x124147a3dULL, 0x1fdd9e132ULL, 0x20d60c12dULL, 0x399da9ca5ULL, 0x06963bcbaULL, 0x22a41aabbULL, 0x1daf88aa4ULL, 0x04e42d72cULL, 0x3befbf733ULL, 0x367366c3cULL, 0x0978f4c23ULL, 0x1033511abULL, 0x2f38c31b4ULL, 0x1615c4f6aULL, 0x291e56f75ULL, 0x3055f32fdULL, 0x0f5e612e2ULL, 0x02c2b89edULL, 0x3dc92a9f2ULL, 0x24828f47aULL, 0x1b891d465ULL, 0x3fbb3c264ULL, 0x00b0ae27bULL, 0x19fb0bff3ULL, 0x26f099fecULL, 0x2b6c404e3ULL, 0x1467d24fcULL, 0x0d2c77974ULL, 0x3227e596bULL, 0x1d1f268dfULL, 0x2214b48c0ULL, 0x3b5f11548ULL, 0x045483557ULL, 0x09c85ae58ULL, 0x36c3c8e47ULL, 0x2f886d3cfULL, 0x1083ff3d0ULL, 0x34b1de5d1ULL, 0x0bba4c5ceULL, 0x12f1e9846ULL, 0x2dfa7b859ULL, 0x2066a2356ULL, 0x1f6d30349ULL, 0x062695ec1ULL, 0x392d07edeULL, 0x2c2b89ed4ULL, 0x13201becbULL, 0x0a6bbe343ULL, 0x35602c35cULL, 0x38fcf5853ULL, 0x07f76784cULL, 0x1ebcc25c4ULL, 0x21b7505dbULL, 0x0585713daULL, 0x3a8ee33c5ULL, 0x23c546e4dULL, 0x1cced4e52ULL, 0x11520d55dULL, 0x2e599f542ULL, 0x37123a8caULL, 0x0819a88d5ULL, 0x27216b961ULL, 0x182af997eULL, 0x01615c4f6ULL, 0x3e6ace4e9ULL, 0x33f617fe6ULL, 0x0cfd85ff9ULL, 0x15b620271ULL, 0x2abdb226eULL, 0x0e8f9346fULL, 0x318401470ULL, 0x28cfa49f8ULL, 0x17c4369e7ULL, 0x1a58ef2e8ULL, 0x25537d2f7ULL, 0x3c18d8f7fULL, 0x03134af60ULL, 0x3a3e4d1beULL, 0x0535df1a1ULL, 0x1c7e7ac29ULL, 0x2375e8c36ULL, 0x2ee931739ULL, 0x11e2a3726ULL, 0x08a906aaeULL, 0x37a294ab1ULL, 0x1390b5cb0ULL, 0x2c9b27cafULL, 0x35d082127ULL, 0x0adb10138ULL, 0x0747c9a37ULL, 0x384c5ba28ULL, 0x2107fe7a0ULL, 0x1e0c6c7bfULL, 0x3134af60bULL, 0x0e3f3d614ULL, 0x177498b9cULL, 0x287f0ab83ULL, 0x25e3d308cULL, 0x1ae841093ULL, 0x03a3e4d1bULL, 0x3ca876d04ULL, 0x189a57b05ULL, 0x2791c5b1aULL, 0x3eda60692ULL, 0x01d1f268dULL, 0x0c4d2bd82ULL, 0x3346b9d9dULL, 0x2a0d1c015ULL, 0x15068e00aULL, 0x000000001ULL, 0x3f0b9201eULL, 0x264037d96ULL, 0x194ba5d89ULL, 0x14d77c686ULL, 0x2bdcee699ULL, 0x32974bb11ULL, 0x0d9cd9b0eULL, 0x29aef8d0fULL, 0x16a56ad10ULL, 0x0feecf098ULL, 0x30e55d087ULL, 0x3d7984b88ULL, 0x027216b97ULL, 0x1b39b361fULL, 0x243221600ULL, 0x0b0ae27b4ULL, 0x3401707abULL, 0x2d4ad5a23ULL, 0x124147a3cULL, 0x1fdd9e133ULL, 0x20d60c12cULL, 0x399da9ca4ULL, 0x06963bcbbULL, 0x22a41aabaULL, 0x1daf88aa5ULL, 0x04e42d72dULL, 0x3befbf732ULL, 0x367366c3dULL, 0x0978f4c22ULL, 0x1033511aaULL, 0x2f38c31b5ULL, 0x1615c4f6bULL, 0x291e56f74ULL, 0x3055f32fcULL, 0x0f5e612e3ULL, 0x02c2b89ecULL, 0x3dc92a9f3ULL, 0x24828f47bULL, 0x1b891d464ULL, 0x3fbb3c265ULL, 0x00b0ae27aULL, 0x19fb0bff2ULL, 0x26f099fedULL, 0x2b6c404e2ULL, 0x1467d24fdULL, 0x0d2c77975ULL, 0x3227e596aULL, 0x1d1f268deULL, 0x2214b48c1ULL, 0x3b5f11549ULL, 0x045483556ULL, 0x09c85ae59ULL, 0x36c3c8e46ULL, 0x2f886d3ceULL, 0x1083ff3d1ULL, 0x34b1de5d0ULL, 0x0bba4c5cfULL, 0x12f1e9847ULL, 0x2dfa7b858ULL, 0x2066a2357ULL, 0x1f6d30348ULL, 0x062695ec0ULL, 0x392d07edfULL, 0x2c2b89ed5ULL, 0x13201becaULL, 0x0a6bbe342ULL, 0x35602c35dULL, 0x38fcf5852ULL, 0x07f76784dULL, 0x1ebcc25c5ULL, 0x21b7505daULL, 0x0585713dbULL, 0x3a8ee33c4ULL, 0x23c546e4cULL, 0x1cced4e53ULL, 0x11520d55cULL, 0x2e599f543ULL, 0x37123a8cbULL, 0x0819a88d4ULL, 0x27216b960ULL, 0x182af997fULL, 0x01615c4f7ULL, 0x3e6ace4e8ULL, 0x33f617fe7ULL, 0x0cfd85ff8ULL, 0x15b620270ULL, 0x2abdb226fULL, 0x0e8f9346eULL, 0x318401471ULL, 0x28cfa49f9ULL, 0x17c4369e6ULL, 0x1a58ef2e9ULL, 0x25537d2f6ULL, 0x3c18d8f7eULL, 0x03134af61ULL, 0x3a3e4d1bfULL, 0x0535df1a0ULL, 0x1c7e7ac28ULL, 0x2375e8c37ULL, 0x2ee931738ULL, 0x11e2a3727ULL, 0x08a906aafULL, 0x37a294ab0ULL, 0x1390b5cb1ULL, 0x2c9b27caeULL, 0x35d082126ULL, 0x0adb10139ULL, 0x0747c9a36ULL, 0x384c5ba29ULL, 0x2107fe7a1ULL, 0x1e0c6c7beULL, 0x3134af60aULL, 0x0e3f3d615ULL, 0x177498b9dULL, 0x287f0ab82ULL, 0x25e3d308dULL, 0x1ae841092ULL, 0x03a3e4d1aULL, 0x3ca876d05ULL, 0x189a57b04ULL, 0x2791c5b1bULL, 0x3eda60693ULL, 0x01d1f268cULL, 0x0c4d2bd83ULL, 0x3346b9d9cULL, 0x2a0d1c014ULL, 0x15068e00bULL}; diff --git a/libbtbb-2015-10-R1/lib/src/uthash.h b/libbtbb-2015-10-R1/lib/src/uthash.h new file mode 100644 index 0000000..d2255b1 --- /dev/null +++ b/libbtbb-2015-10-R1/lib/src/uthash.h @@ -0,0 +1,960 @@ +/* +Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#define DECLTYPE(x) +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined (_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#else +#include +#endif + +#define UTHASH_VERSION 1.9.9 + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + out=NULL; \ + if (head) { \ + unsigned _hf_bkt,_hf_hashv; \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0 +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + replaced=NULL; \ + HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ + if (replaced!=NULL) { \ + HASH_DELETE(hh,head,replaced); \ + } \ + HASH_ADD(hh,head,fieldname,keylen_in,add); \ +} while(0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + unsigned _hd_bkt; \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ + HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count; \ + char *_prev; \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %u, actual %u\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619; \ + } \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned char *_hj_key=(unsigned char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned char *_sfh_key=(unsigned char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if ((out)->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + if (_hs_p){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e) { \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail){ \ + _hs_tail->next = NULL; \ + } \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#define HASH_OVERHEAD(hh,head) \ + ((head) ? ( \ + (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + (sizeof(UT_hash_table)) + \ + (HASH_BLOOM_BYTELEN)))) : 0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/libbtbb-2015-10-R1/packaging/Portfile b/libbtbb-2015-10-R1/packaging/Portfile new file mode 100644 index 0000000..4001cd1 --- /dev/null +++ b/libbtbb-2015-10-R1/packaging/Portfile @@ -0,0 +1,34 @@ +# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 +# $Id$ + +PortSystem 1.0 +PortGroup cmake 1.0 +PortGroup github 1.0 + +github.setup greatscottgadgets libbtbb 2014-02-R2 +categories net security +platforms darwin +maintainers gmail.com:dominicgs +license GPL-2+ + +description Bluetooth Baseband Decoding Library + +long_description \ + LibBTBB is a Bluetooth Baseband processing library that supports Basic \ + Rate and Bluetooth Smart (BLE) packets. It is used by the Ubertooth and \ + gr-bluetooth packet sniffer implementations. + +homepage https://github.com/greatscottgadgets/libbtbb + +checksums rmd160 0adc5d59e611509cdcf8959be8b6e31704529e48 \ + sha256 04a187b6f17836437e5f9deecb0b643c75ec0eafce671e373d1d4c13fc104984 + +configure.dir ${workpath}/build +build.dir ${configure.dir} + +post-extract { + file mkdir ${configure.dir} +} + +configure.post_args ../${name}-${version} +configure.args-append -DPACKAGE_MANAGER=1 \ No newline at end of file diff --git a/libbtbb-2015-10-R1/packaging/libbtbb.rb b/libbtbb-2015-10-R1/packaging/libbtbb.rb new file mode 100644 index 0000000..6a905d4 --- /dev/null +++ b/libbtbb-2015-10-R1/packaging/libbtbb.rb @@ -0,0 +1,26 @@ +require "formula" + +class Libbtbb < Formula + homepage "https://github.com/greatscottgadgets/libbtbb" + url "https://github.com/greatscottgadgets/libbtbb/archive/2014-02-R2.tar.gz" + sha1 "aa94b7d92465704aa647123f11e906491a26d090" + version "2014-02-R2" + + head "https://github.com/greatscottgadgets/libbtbb.git" + + option :universal + + depends_on "cmake" => :build + depends_on :python + + def install + if build.universal? + ENV.universal_binary + ENV["CMAKE_OSX_ARCHITECTURES"] = Hardware::CPU.universal_archs.as_cmake_arch_flags + end + mkdir "build" do + system "cmake", "..", *std_cmake_args + system "make", "install" + end + end +end diff --git a/libbtbb-2015-10-R1/packaging/libbtbb.spec b/libbtbb-2015-10-R1/packaging/libbtbb.spec new file mode 100644 index 0000000..fff4233 --- /dev/null +++ b/libbtbb-2015-10-R1/packaging/libbtbb.spec @@ -0,0 +1,64 @@ +# +#Copyright 2013 Dominic Spill +# +#This file is part of libbtbb +# +#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, 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 libbtbb; see the file COPYING. If not, write to +#the Free Software Foundation, Inc., 51 Franklin Street, +#Boston, MA 02110-1301, USA. +# + +Summary: Bluetooth baseband library +Name: libbtbb +Version: 2013.06 +Release: 1 +Summary: A Bluetooth basebad decoding library +License: GPLv2 +URL: http://mooedit.sourceforge.net/ +Source: %{name}-%{version}.tar.gz + +BuildRequires: cmake gcc python + +Autoreqprov: on + +%description +A library for decoding and processing Bluetooth baseband packets. +It can be used with any raw bitstream receiver, such as Ubertooth or +gr-bluetooth. + +%prep +%setup -q +%build +cmake -DCMAKE_SKIP_RPATH=ON \ + -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DBUILD_ROOT=%{buildroot} + +%{__make} %{?jobs:-j%jobs} + +%install +%{__make} DESTDIR=%{buildroot} install + +%files +%{_prefix}/lib/libbtbb.so +%{_prefix}/lib/libbtbb.so.0 +%{_prefix}/lib/libbtbb.so.0.2.0 +%{_prefix}/lib/python* +%{_bindir}/btaptap +%{_libdir}/../include/libbtbb/bluetooth_le_packet.h +%{_libdir}/../include/libbtbb/btbb.h +%doc COPYING README.md + +%changelog +* Thu Jun 06 2013 Dominic Spill - 0.2.0 +- First binary release diff --git a/libbtbb-2015-10-R1/python/CMakeLists.txt b/libbtbb-2015-10-R1/python/CMakeLists.txt new file mode 100644 index 0000000..3422394 --- /dev/null +++ b/libbtbb-2015-10-R1/python/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright 2013 Dominic Spill +# +# This file is part of Libbtbb +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +project(btbb-python) + +# Check for python installation +find_package(PythonInterp) +if(NOT PYTHONINTERP_FOUND) + return() +else() + add_subdirectory(pcaptools) +endif() + +# Create uninstall target +if(NOT libbtbb_all_SOURCE_DIR) + configure_file( + ${PROJECT_SOURCE_DIR}/../cmake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake + @ONLY) + + add_custom_target(uninstall + ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake + ) +endif() diff --git a/libbtbb-2015-10-R1/python/pcaptools/CMakeLists.txt b/libbtbb-2015-10-R1/python/pcaptools/CMakeLists.txt new file mode 100644 index 0000000..78cfec9 --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright 2013 Dominic Spill +# +# This file is part of Libbtbb (pcapdump) +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +set(SETUP_PY_IN ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in) +set(SETUP_PY ${CMAKE_CURRENT_BINARY_DIR}/setup.py) +set(DEPS ${CMAKE_CURRENT_SOURCE_DIR}/pcapdump/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/pcapdump/pcapdump.py) +set(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/build) + +configure_file(${SETUP_PY_IN} ${SETUP_PY}) + +add_custom_command(OUTPUT ${OUTPUT}/timestamp + COMMAND ${PYTHON_EXECUTABLE} setup.py build + COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT}/timestamp + DEPENDS ${DEPS}) + +add_custom_target(pcapdump ALL DEPENDS ${OUTPUT}/timestamp) +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} build -b ${OUTPUT} install --prefix=${BUILD_ROOT}/${CMAKE_INSTALL_PREFIX})") + +add_custom_target(btaptap ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/btaptap) +install(PROGRAMS btaptap DESTINATION ${INSTALL_DEFAULT_BINDIR}) + diff --git a/libbtbb-2015-10-R1/python/pcaptools/Makefile b/libbtbb-2015-10-R1/python/pcaptools/Makefile new file mode 100644 index 0000000..f76569e --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/Makefile @@ -0,0 +1,39 @@ +# Copyright 2012 Michael Ossmann, Dominic Spill +# +# This file is part of Project Ubertooth. +# +# 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, 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +INSTALL ?= /usr/bin/install +PYTHON ?= /usr/bin/env python + +INSTALL_DIR ?= /usr/bin + +EXECUTABLE_FILES = btaptap + +all: pcapdump + +pcapdump: + $(PYTHON) setup.py build + +clean: + rm -rf build + +install: pcapdump + $(PYTHON) setup.py install + $(INSTALL) -m 0755 $(EXECUTABLE_FILES) $(INSTALL_DIR) + +.PHONY: all clean install pcapdump diff --git a/libbtbb-2015-10-R1/python/pcaptools/README b/libbtbb-2015-10-R1/python/pcaptools/README new file mode 100644 index 0000000..9c79bf5 --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/README @@ -0,0 +1,20 @@ +This directory contains supplemental tools for working with pcap files produced +by libbtbb. (Actually libbtbb doesn't produce such files by itself at this +time, but you can produce them with the Ubertooth tools. + +These tools are not automatically installed as part of the libbtbb +installation but can be used right out of this directory or manually installed. + +pcapdump: a Python module for pcap + +Pcapdump us used by btaptap to read and write pcap files. It should work with +python 2.4 and above (python 3 support requires using the 2to3 tool). + + +btaptap: a Bluetooth keyboard sniffer + +Many Bluetooth keyboards operate by default in "boot mode" which features +simplified HID messaging that can be interpreted, for example, by a PC BIOS. +Some of those keyboards also transmit these messages over unencrypted +Bluetooth. This tool can be used to extract keystrokes from such +transmissions. diff --git a/libbtbb-2015-10-R1/python/pcaptools/btaptap b/libbtbb-2015-10-R1/python/pcaptools/btaptap new file mode 100755 index 0000000..67b6f25 --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/btaptap @@ -0,0 +1,520 @@ +#!/usr/bin/env python +# +# Copyright 2009 Joshua Wright, Michael Ossmann +# +# This file is part of gr-bluetooth +# +# gr-bluetooth 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, or (at your option) +# any later version. +# +# gr-bluetooth 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 gr-bluetooth; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import sys +import struct +import time +from pcapdump.pcapdump import * + +DLT_EN10MB = 1 +DLT_BLUETOOTH_HCI_H4 = 187 +ELLISYS_CSV_HDR = "\"Depth\",\"Time\",\"Name\",\"Data\"\x0d\x0a" +ELLISYS_HID_INPUT = "HID Input 1" +USBHID_MAP = { + 0x04 : "a", + 0x05 : "b", + 0x06 : "c", + 0x07 : "d", + 0x08 : "e", + 0x09 : "f", + 0x0A : "g", + 0x0B : "h", + 0x0C : "i", + 0x0D : "j", + 0x0E : "k", + 0x0F : "l", + 0x10 : "m", + 0x11 : "n", + 0x12 : "o", + 0x13 : "p", + 0x14 : "q", + 0x15 : "r", + 0x16 : "s", + 0x17 : "t", + 0x18 : "u", + 0x19 : "v", + 0x1A : "w", + 0x1B : "x", + 0x1C : "y", + 0x1D : "z", + 0x1E : "1", + 0x1F : "2", + 0x20 : "3", + 0x21 : "4", + 0x22 : "5", + 0x23 : "6", + 0x24 : "7", + 0x25 : "8", + 0x26 : "9", + 0x27 : "0", + 0x28 : "[Return]\n", + 0x29 : "[Esc]", + 0x2A : "[Backspace]", + 0x2B : "[Tab]\t", + 0x2C : " ", + 0x2D : "-", + 0x2E : "=", + 0x2F : "[", + 0x30 : "]", + 0x31 : "\\", + 0x32 : "#", + 0x33 : ";", + 0x34 : "'", + 0x35 : "[Grave Accent]", + 0x36 : ",", + 0x37 : ".", + 0x38 : "/", + 0x39 : "[Caps Lock]", + 0x3A : "[F1]", + 0x3B : "[F2]", + 0x3C : "[F3]", + 0x3D : "[F4]", + 0x3E : "[F5]", + 0x3F : "[F6]", + 0x40 : "[F7]", + 0x41 : "[F8]", + 0x42 : "[F9]", + 0x43 : "[F10]", + 0x44 : "[F11]", + 0x45 : "[F12]", + 0x46 : "[PrintScreen]", + 0x47 : "[Scroll]", + 0x48 : "[Pause]", + 0x49 : "[Insert]", + 0x4A : "[Home]", + 0x4B : "[PageUp]", + 0x4C : "[Delete]", + 0x4D : "[End]", + 0x4E : "[PageDown]", + 0x4F : "[RightArrow]", + 0x50 : "[LeftArrow]", + 0x51 : "[DownArrow]", + 0x52 : "[UpArrow]", + 0x53 : "[Keypad Num Lock and Clear]", + 0x54 : "[Keypad /]", + 0x55 : "[Keypad *]", + 0x56 : "[Keypad -]", + 0x57 : "[Keypad +]", + 0x58 : "[Keypad Enter]\n", + 0x59 : "[Keypad 1 and End]", + 0x5A : "[Keypad 2 and Down Arrow]", + 0x5B : "[Keypad 3 and PageDn]", + 0x5C : "[Keypad 4 and Left Arrow]", + 0x5D : "[Keypad 5]", + 0x5E : "[Keypad 6 and Right Arrow]", + 0x5F : "[Keypad 7 and Home]", + 0x60 : "[Keypad 8 and Up Arrow]", + 0x61 : "[Keypad 9 and PageUp]", + 0x62 : "[Keypad 0 and Insert]", + 0x63 : "[Keypad . and Delete]", + 0x64 : "\\", + 0x65 : "[WinKey]", + 0x66 : "[Power9]", + 0x67 : "[Keypad =]", + 0x68 : "[F13]", + 0x69 : "[F14]", + 0x6A : "[F15]", + 0x6B : "[F16]", + 0x6C : "[F17]", + 0x6D : "[F18]", + 0x6E : "[F19]", + 0x6F : "[F20]", + 0x70 : "[F21]", + 0x71 : "[F22]", + 0x72 : "[F23]", + 0x73 : "[F24]", + 0x74 : "[Execute]", + 0x75 : "[Help]", + 0x76 : "[Menu]", + 0x77 : "[Select]", + 0x78 : "[Stop]", + 0x79 : "[Again]", + 0x7A : "[Undo]", + 0x7B : "[Cut]", + 0x7C : "[Copy]", + 0x7D : "[Paste]", + 0x7E : "[Find]", + 0x7F : "[Mute]", + 0x80 : "[Volume Up]", + 0x81 : "[Volume Down]", + 0x82 : "[Locking Caps Lock]", + 0x83 : "[Locking Num Lock]", + 0x84 : "[Locking Scroll Lock]", + 0x85 : "[Keypad Comma]", + 0x86 : "[Keypad Equal]", + 0x87 : "[International1]", + 0x88 : "[International2]", + 0x89 : "[International3]", + 0x8A : "[International4]", + 0x8B : "[International5]", + 0x8C : "[International6]", + 0x8D : "[International7]", + 0x8E : "[International8]", + 0x8F : "[International9]", + 0x90 : "[LANG1]", + 0x91 : "[LANG2]", + 0x92 : "[LANG3]", + 0x93 : "[LANG4]", + 0x94 : "[LANG5]", + 0x95 : "[LANG6]", + 0x96 : "[LANG7]", + 0x97 : "[LANG8]", + 0x98 : "[LANG9]", + 0x99 : "[Alternate Erase]", + 0x9A : "[SysReq/Attention]", + 0x9B : "[Cancel]", + 0x9C : "[Clear]", + 0x9D : "[Prior]", + 0x9E : "[Return]\n", + 0x9F : "[Separator]", + 0xA0 : "[Out]", + 0xA1 : "[Oper]", + 0xA2 : "[Clear/Again]", + 0xA3 : "[CrSel/Props]", + 0xA4 : "[ExSel]", + 0xB0 : "[Keypad 00]", + 0xB1 : "[Keypad 000]", + 0xB2 : "[Thousands Separator]", + 0xB3 : "[Decimal Separator]", + 0xB4 : "[Currency Unit]", + 0xB5 : "[Currency Sub-unit]", + 0xB6 : "[Keypad (]", + 0xB7 : "[Keypad )]", + 0xB8 : "[Keypad {]", + 0xB9 : "[Keypad }]", + 0xBA : "[Keypad Tab]\t", + 0xBB : "[Keypad Backspace]", + 0xBC : "[Keypad A]", + 0xBD : "[Keypad B]", + 0xBE : "[Keypad C]", + 0xBF : "[Keypad D]", + 0xC0 : "[Keypad E]", + 0xC1 : "[Keypad F]", + 0xC2 : "[Keypad XOR]", + 0xC3 : "[Keypad ^]", + 0xC4 : "[Keypad %]", + 0xC5 : "[Keypad <]", + 0xC6 : "[Keypad >]", + 0xC7 : "[Keypad &]", + 0xC8 : "[Keypad &&]", + 0xC9 : "[Keypad |]", + 0xCA : "[Keypad ||]", + 0xCB : "[Keypad :]", + 0xCC : "[Keypad #]", + 0xCD : "[Keypad Space]", + 0xCE : "[Keypad @]", + 0xCF : "[Keypad !]", + 0xD0 : "[Keypad Memory Store]", + 0xD1 : "[Keypad Memory Recall]", + 0xD2 : "[Keypad Memory Clear]", + 0xD3 : "[Keypad Memory Add]", + 0xD4 : "[Keypad Memory Subtract]", + 0xD5 : "[Keypad Memory Multiply]", + 0xD6 : "[Keypad Memory Divide]", + 0xD7 : "[Keypad +/-]", + 0xD8 : "[Keypad Clear]", + 0xD9 : "[Keypad Clear Entry]", + 0xDA : "[Keypad Binary]", + 0xDB : "[Keypad Octal]", + 0xDC : "[Keypad Decimal]", + 0xDD : "[Keypad Hexadecimal]", + 0xE0 : "[LeftControl]", + 0xE1 : "[LeftShift]", + 0xE2 : "[LeftAlt]", + 0xE3 : "[LeftWinKey]", + 0xE4 : "[RightControl]", + 0xE5 : "[RightShift]", + 0xE6 : "[RightAlt]", + 0xE7 : "[RightWinKey]" +} + +# some keycodes represent different things when Shift is held down +USBHID_SHIFT_MAP = { + 0x04 : "A", + 0x05 : "B", + 0x06 : "C", + 0x07 : "D", + 0x08 : "E", + 0x09 : "F", + 0x0A : "G", + 0x0B : "H", + 0x0C : "I", + 0x0D : "J", + 0x0E : "K", + 0x0F : "L", + 0x10 : "M", + 0x11 : "N", + 0x12 : "O", + 0x13 : "P", + 0x14 : "Q", + 0x15 : "R", + 0x16 : "S", + 0x17 : "T", + 0x18 : "U", + 0x19 : "V", + 0x1A : "W", + 0x1B : "X", + 0x1C : "Y", + 0x1D : "Z", + 0x1E : "!", + 0x1F : "@", + 0x20 : "#", + 0x21 : "$", + 0x22 : "%", + 0x23 : "^", + 0x24 : "&", + 0x25 : "*", + 0x26 : "(", + 0x27 : ")", + 0x2D : "_", + 0x2E : "+", + 0x2F : "{", + 0x30 : "}", + 0x31 : "|", + 0x32 : "~", + 0x33 : ":", + 0x34 : "\"", + 0x35 : "~", + 0x36 : "<", + 0x37 : ">", + 0x38 : "?", + 0x64 : "|" +} + +# global variable to track currently depressed keys +active_keys = [] + +def hid2ascii(scancode, shift): + ''' + Convert the specified scancode value to the ASCII equivalent using the + USBHID_MAP list. + ''' + if shift: + try: + code = USBHID_SHIFT_MAP[scancode] + return code + except KeyError: + pass + try: + code = USBHID_MAP[scancode] + except KeyError: + return "[Reserved]" + return code + +def usage(): + print >>sys.stderr, "Usage: btaptap [-r pcapfile.pcap | -e ellisysfile.csv] [-c count] [-h]\n" + sys.exit(0) + +def parse_l2cap_keydata(l2cappkt): + global active_keys + + TRANS_HDR_IN_DATA = 0xA1 + REPORT_ID_KEYBOARD = 0x01 + CTRL = 1 + SHIFT = 2 + ALT = 4 + GUI = 8 + + # Keyboard keystrokes are only seen in L2CAP packets at least 10 bytes long + l2clen = (ord(l2cappkt[1]) << 8) | ord(l2cappkt[0]) + if l2clen < 10: + return + + # Keyboard keystrokes are only carried by Channel ID >= 0x40 + cid = (ord(l2cappkt[3]) << 8) | ord(l2cappkt[2]) + if cid < 0x40: + return + # Ideally we would check for the particular CID for the HID_INTERRUPT + # channel, but we don't handle the negotiation (and may not have even + # seen it). + + # Transaction Header should indicate input data + thdr = ord(l2cappkt[4]) + if thdr != TRANS_HDR_IN_DATA: + return + + # Report ID should indicate this is a keyboard + rid = ord(l2cappkt[5]) + if rid != REPORT_ID_KEYBOARD: + return + + # This byte describes modifier key status (one bit per key) + mod = ord(l2cappkt[6]) + + # We don't care whether left or right modifier keys are pressed, so we + # combine the status bits. + leftmod = mod & 0x0f + rightmod = (mod & 0xf0) >> 4 + mod = leftmod | rightmod + + # up to six keys can be reported at once + keycodes = [] + #for byte in range(8,14): + for byte in range(8,11): + keystroke = ord(l2cappkt[byte]) + if keystroke != 0x00: + keycodes.append(keystroke) + + for keystroke in keycodes: + # don't repeat keys that are still held down + if active_keys.count(keystroke) == 0: + + if (mod & CTRL): + sys.stdout.write("CTRL^") + if (mod & ALT): + sys.stdout.write("ALT^") + if (mod & GUI): # e.g. Windows key + sys.stdout.write("GUI^") + + sys.stdout.write(hid2ascii(keystroke, mod & SHIFT)) + + active_keys = keycodes + +def parse_ellisys_export(exportfile): + try: + cap = open(exportfile, "r") + except (OSError, IOError) as e: + print >>sys.stderr, "Unable to open Ellisys capture file." + return + + # Check to make sure the CSV file header matches out expectations + hdr=cap.readline() + if (hdr != ELLISYS_CSV_HDR): + print >>sys.stderr, "Invalid CSV file (does not match Ellisys export format)" + return + + for packetline in cap.xreadlines(): + try: + (edepth, etime, ename, edata) = packetline.replace('"', '').strip().split(",") + except ValueError: + continue + + # We are only interedted in HID Input data + if (ename != ELLISYS_HID_INPUT): continue + + parse_ellisys_keydata(edata) + +def parse_ellisys_keydata(payload): + TRANS_HDR_IN_DATA = "\xA1" + DEST_CHANNEL_ID = "\x06\x03" + + # Convert space-separated hex into string + payload = payload.replace(' ','').decode("hex") + + # The Ellisys CSV file format doesn't give us the L2CAP data, so we fake it here by adding + # a 2-byte length field, destination CID, and transaction header + packet = chr(len(payload)+1) + "\x00" + DEST_CHANNEL_ID + TRANS_HDR_IN_DATA + payload + parse_l2cap_keydata(packet) + +def parse_bb_keydata(packet): + + BTBBHDR_TYPE_MASK = 0x78 + BTBBHDR_TYPE_SHIFT = 3 + BTBBHDR_TYPE_DM1 = 3 + BTBBPAYLOADHDR_LLID_MASK = 0x03 + BTBBPAYLOADHDR_LLID_SHIFT = 0 + BTBBPAYLOADHDR_LEN_MASK = 0xF8 + BTBBPAYLOADHDR_LEN_SHIFT = 3 + LLID_L2CAP = 2 + + # Keyboard keystrokes are only seen in frames at least 40 bytes long + if len(packet) < 40: + return + + # Keyboard keystrokes are only seen in DM1 frames + btbbhdr = packet[20:23] + type = (ord(btbbhdr[0]) & BTBBHDR_TYPE_MASK) >> BTBBHDR_TYPE_SHIFT + if type != BTBBHDR_TYPE_DM1: + return + + # Keyboard keystrokes are only seen in L2CAP packets 14 bytes long + btbbpayloadhdr = ord(packet[23]) + llid = btbbpayloadhdr & (BTBBPAYLOADHDR_LLID_MASK) >> BTBBPAYLOADHDR_LLID_SHIFT + l2clen = (btbbpayloadhdr & BTBBPAYLOADHDR_LEN_MASK) >> BTBBPAYLOADHDR_LEN_SHIFT + #print "Debug btbbpayloadhdr 0x%02x, llid %d, l2clen %d"%(btbbpayloadhdr, llid, l2clen) + if llid != LLID_L2CAP or l2clen < 14: + return + + parse_l2cap_keydata(packet[24:38]) + +def parse_hci_keydata(packet): + + HCI_TYPE_ACL_DATA = 2 + + # Keyboard keystrokes are only seen in frames at least 19 bytes long + if len(packet) < 19: + return + + # Keyboard keystrokes are only seen in ACL Data frames + type = ord(packet[0]) + if type != HCI_TYPE_ACL_DATA: + return + + parse_l2cap_keydata(packet[5:]) + +if __name__ == '__main__': + + arg_pcapfile = None + arg_ellisysfile = None + arg_count = -1 + packetcount = 0 + + while len(sys.argv) > 1: + op = sys.argv.pop(1) + if op == '-r': + arg_pcapfile = sys.argv.pop(1) + if op == '-c': + arg_count = int(sys.argv.pop(1)) + if op == '-e': + arg_ellisysfile = sys.argv.pop(1) + if op == '-h': + usage() + sys.exit(0) + + if (arg_ellisysfile == None and arg_pcapfile == None): + print >>sys.stderr, "Must specify a libpcap capture or an Ellisys CSV file" + usage() + sys.exit(0) + + if arg_pcapfile != None: + cap = PcapReader(arg_pcapfile) + + while arg_count != packetcount: + try: + (pheader, packet) = cap.pnext() + pkttime = pheader[0] + packetcount+=1 + + if cap.datalink() == DLT_EN10MB: + parse_bb_keydata(packet) + elif cap.datalink() == DLT_BLUETOOTH_HCI_H4: + parse_hci_keydata(packet) + else: + print >>sys.stderr, "Unsupported libpcap data link layer: %d\n" % cap.datalink() + except TypeError: # raised when pnext returns Null (end of capture) + break + + cap.close() + + if arg_ellisysfile != None: + parse_ellisys_export(arg_ellisysfile) + + print diff --git a/libbtbb-2015-10-R1/python/pcaptools/pcapdump/__init__.py b/libbtbb-2015-10-R1/python/pcaptools/pcapdump/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libbtbb-2015-10-R1/python/pcaptools/pcapdump/pcapdump.py b/libbtbb-2015-10-R1/python/pcaptools/pcapdump/pcapdump.py new file mode 100644 index 0000000..647fc60 --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/pcapdump/pcapdump.py @@ -0,0 +1,193 @@ +# Copyright 2009 Joshua Wright +# +# This file is part of gr-bluetooth +# +# gr-bluetooth 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, or (at your option) +# any later version. +# +# gr-bluetooth 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 gr-bluetooth; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import struct +import time + +PCAPH_MAGIC_NUM = 0xa1b2c3d4 +PCAPH_VER_MAJOR = 2 +PCAPH_VER_MINOR = 4 +PCAPH_THISZONE = 0 +PCAPH_SIGFIGS = 0 +PCAPH_SNAPLEN = 65535 + +class PcapReader: + + def __init__(self, savefile): + ''' + Opens the specified file, validates a libpcap header is present. + @type savefile: String + @param savefile: Input libpcap filename to open + @rtype: None + ''' + PCAPH_LEN = 24 + self.__fh = open(savefile, mode='rb') + self._pcaphsnaplen = 0 + header = self.__fh.read(PCAPH_LEN) + + # Read the first 4 bytes for the magic number, determine endianness + magicnum = struct.unpack("I", header[0:4])[0] + if magicnum != 0xd4c3b2a1: + # Little endian + self.__endflag = "<" + elif magicnum == 0xa1b2c3d4: + # Big endign + self.__endflag = ">" + else: + raise Exception('Specified file is not a libpcap capture') + + pcaph = struct.unpack("%sIHHIIII"%self.__endflag, header) + if pcaph[1] != PCAPH_VER_MAJOR and pcaph[2] != PCAPH_VER_MINOR \ + and pcaph[3] != PCAPH_THISZONE and pcaph[4] != PCAPH_SIGFIGS \ + and pcaph[5] != PCAPH_SNAPLEN: + raise Exception('Unsupported pcap header format or version') + + self._pcaphsnaplen = pcaph[5] + self._datalink = pcaph[6] + + def datalink(self): + return self._datalink + + def close(self): + ''' + Closes the output packet capture; wrapper for pcap_close(). + @rtype: None + ''' + self.pcap_close() + + def pcap_close(self): + ''' + Closes the output packet capture. + @rtype: None + ''' + self.__fh.close() + + def pnext(self): + ''' + Wrapper for pcap_next to mimic method for Daintree SNA + ''' + return self.pcap_next() + + def pcap_next(self): + ''' + Retrieves the next packet from the capture file. Returns a list of + [Hdr, packet] where Hdr is a list of [timestamp, snaplen, plen] and + packet is a string of the payload content. Returns None at the end + of the packet capture. + @rtype: List + ''' + # Read the next header block + PCAPH_RECLEN = 16 + rechdrdata = self.__fh.read(PCAPH_RECLEN) + + try: + rechdrtmp = struct.unpack("%sIIII"%self.__endflag, rechdrdata) + except struct.error: + return [None,None] + + rechdr = [ + float("%s.%s"%(rechdrtmp[0],rechdrtmp[1])), + rechdrtmp[2], + rechdrtmp[3] + ] + if rechdr[1] > rechdr[2] or rechdr[1] > self._pcaphsnaplen or rechdr[2] > self._pcaphsnaplen: + raise Exception('Corrupted or invalid libpcap record header (included length exceeds actual length)') + + # Read the included packet length + frame = self.__fh.read(rechdr[1]) + return [rechdr, frame] + + +class PcapDumper: + + def __init__(self, datalink, savefile): + ''' + Creates a libpcap file using the specified datalink type. + @type datalink: Integer + @param datalink: Datalink type, one of DLT_* defined in pcap-bpf.h + @type savefile: String + @param savefile: Output libpcap filename to open + @rtype: None + ''' + self.__fh = open(savefile, mode='wb') + self.__fh.write(''.join([ + struct.pack("I", PCAPH_MAGIC_NUM), + struct.pack("H", PCAPH_VER_MAJOR), + struct.pack("H", PCAPH_VER_MINOR), + struct.pack("I", PCAPH_THISZONE), + struct.pack("I", PCAPH_SIGFIGS), + struct.pack("I", PCAPH_SNAPLEN), + struct.pack("I", datalink) + ])) + + def pcap_dump(self, packet, ts_sec=None, ts_usec=None, orig_len=None): + ''' + Appends a new packet to the libpcap file. Optionally specify ts_sec + and tv_usec for timestamp information, otherwise the current time is + used. Specify orig_len if your snaplen is smaller than the entire + packet contents. + @type ts_sec: Integer + @param ts_sec: Timestamp, number of seconds since Unix epoch. Default + is the current timestamp. + @type ts_usec: Integer + @param ts_usec: Timestamp microseconds. Defaults to current timestamp. + @type orig_len: Integer + @param orig_len: Length of the original packet, used if the packet you + are writing is smaller than the original packet. Defaults to the + specified packet's length. + @type packet: String + @param packet: Packet contents + @rtype: None + ''' + + if ts_sec == None or ts_usec == None: + # There must be a better way here that I don't know -JW + s_sec, s_usec = str(time.time()).split(".") + ts_sec = int(s_sec) + ts_usec = int(s_usec) + + if orig_len == None: + orig_len = len(packet) + + plen = len(packet) + + self.__fh.write(''.join([ + struct.pack("I", ts_sec), + struct.pack("I", ts_usec), + struct.pack("I", orig_len), + struct.pack("I", plen), + packet + ])) + + return + + + def close(self): + ''' + Closes the output packet capture; wrapper for pcap_close(). + @rtype: None + ''' + self.pcap_close() + + def pcap_close(self): + ''' + Closed the output packet capture. + @rtype: None + ''' + self.__fh.close() diff --git a/libbtbb-2015-10-R1/python/pcaptools/setup.py b/libbtbb-2015-10-R1/python/pcaptools/setup.py new file mode 100755 index 0000000..bd7a928 --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/setup.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +""" +pcapdump setup + +Install script for pcapdump + +Usage: python setup.py install + +This file is part of libbtbb +Copyright 2012 Dominic Spill +""" + +from distutils.core import setup + +setup( + name = "pcapdump", + version = "0.8", + description = "A reader and dump utility for Pcap files", + author = "Joshua Wright", + url = "https://sourceforge.net/projects/libbtbb/", + license = "GPL", + packages = ['pcapdump'], + classifiers=[ + 'Development Status :: 5 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Programming Language :: Python', + 'Operating System :: OS Independent', + 'Topic :: System :: Networking :: Monitoring', + ], +) diff --git a/libbtbb-2015-10-R1/python/pcaptools/setup.py.in b/libbtbb-2015-10-R1/python/pcaptools/setup.py.in new file mode 100755 index 0000000..79196d0 --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/setup.py.in @@ -0,0 +1,32 @@ +#!/usr/bin/env python +""" +pcapdump setup + +Install script for pcapdump + +Usage: python setup.py install + +This file is part of libbtbb +Copyright 2012-2013 Dominic Spill +""" + +from distutils.core import setup + +setup( + name = "pcapdump", + description = "A reader and dump utility for Pcap files", + author = "Joshua Wright", + url = "https://sourceforge.net/projects/libbtbb/", + license = "GPL", + version = '${PACKAGE_VERSION}', + package_dir = { '': '${CMAKE_CURRENT_SOURCE_DIR}' }, + packages = ['pcapdump'], + classifiers=[ + 'Development Status :: 5 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Programming Language :: Python', + 'Operating System :: OS Independent', + 'Topic :: System :: Networking :: Monitoring', + ], +) diff --git a/libbtbb-2015-10-R1/python/pcaptools/tests/ellysis-keyboard.csv b/libbtbb-2015-10-R1/python/pcaptools/tests/ellysis-keyboard.csv new file mode 100644 index 0000000..3c53b2b --- /dev/null +++ b/libbtbb-2015-10-R1/python/pcaptools/tests/ellysis-keyboard.csv @@ -0,0 +1,866 @@ +"Depth","Time","Name","Data" +"0","7.248613000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","7.249863000","HID Input 1","01 00 00 28 00 00 00 00 00" +"0","7.251113000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","10.646359000","HID Input 1","01 00 00 28 00 00 00 00 00" +"0","10.658858750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","10.681358750","HID Input 1","01 00 00 28 00 00 00 00 00" +"0","10.758865000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","10.893876750","HID Input 1","01 00 00 28 00 00 00 00 00" +"0","10.983884250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","12.558997750","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","13.009032500","HID Input 1","01 02 00 08 00 00 00 00 00" +"0","13.144044625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","13.189048625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","13.324059500","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","13.414067500","HID Input 1","01 00 00 11 17 00 00 00 00" +"0","13.459070500","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","13.504074375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","13.549077875","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","13.594078750","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","13.684083375","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","13.729087500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","13.774091625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","13.864099125","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","13.865349125","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","13.954107375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","13.955357375","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","13.999108000","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","14.044112125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","14.089117000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","14.134119250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","14.269131375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","14.270381375","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","14.404141250","HID Input 1","01 02 00 17 00 00 00 00 00" +"0","14.449145125","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","14.584155625","HID Input 1","01 02 00 06 00 00 00 00 00" +"0","14.674164250","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","14.675414250","HID Input 1","01 02 00 13 00 00 00 00 00" +"0","14.809176000","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","14.854179250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","14.855429250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","14.944184000","HID Input 1","01 00 00 2C 16 00 00 00 00" +"0","14.989186250","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","15.034189500","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","15.079194375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","15.169201125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","15.214205250","HID Input 1","01 00 00 14 00 00 00 00 00" +"0","15.349217625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","15.350467625","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","15.394222125","HID Input 1","01 00 00 18 08 00 00 00 00" +"0","15.439224500","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","15.484228000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","15.619238750","HID Input 1","01 00 00 11 06 00 00 00 00" +"0","15.620488750","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","15.709246125","HID Input 1","01 00 00 06 08 00 00 00 00" +"0","15.710496125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","15.754250625","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","15.799253375","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","15.844256875","HID Input 1","01 00 00 2C 11 00 00 00 00" +"0","15.889262250","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","15.934265375","HID Input 1","01 00 00 11 18 00 00 00 00" +"0","15.979269125","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","16.024272875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","16.114280375","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","16.249286750","HID Input 1","01 00 00 10 05 00 00 00 00" +"0","16.294289875","HID Input 1","01 00 00 05 00 00 00 00 00" +"0","16.295540000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","16.384296125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","16.474304000","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","16.519306375","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","16.564310750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","16.834333625","HID Input 1","01 20 00 00 00 00 00 00 00" +"0","16.924341375","HID Input 1","01 20 00 33 00 00 00 00 00" +"0","17.014348625","HID Input 1","01 00 00 33 00 00 00 00 00" +"0","17.059353250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","17.194365625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","17.329375625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","17.330625625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","17.419381000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","17.420631000","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","17.509384500","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","17.510634375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","17.554388500","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","17.599393125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","17.689399750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","17.734403750","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","17.869416125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","17.870666125","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","17.959421875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","18.004424875","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","18.184440500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","18.185690625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","18.274448625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","18.319453375","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","18.409461000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","18.454464375","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","18.544471500","HID Input 1","01 00 00 06 12 00 00 00 00" +"0","18.545721500","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","18.634478875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","18.724483000","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","18.814490375","HID Input 1","01 00 00 0F 2C 00 00 00 00" +"0","18.859493750","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","18.949501375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","18.994505500","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","19.129516125","HID Input 1","01 00 00 18 16 00 00 00 00" +"0","19.130766250","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","19.219524125","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","19.220773875","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","19.309531000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","19.354534125","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","19.444542000","HID Input 1","01 00 00 16 2C 00 00 00 00" +"0","19.445792000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","19.579553625","HID Input 1","01 00 00 2C 16 00 00 00 00" +"0","19.580803625","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","19.669561125","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","19.714563625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","19.759568375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","19.850826125","HID Input 1","01 00 00 14 00 00 00 00 00" +"0","19.939581000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","19.940831125","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","20.029584250","HID Input 1","01 00 00 18 08 00 00 00 00" +"0","20.074588375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","20.075838500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","20.164594500","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","20.209599125","HID Input 1","01 00 00 11 06 00 00 00 00" +"0","20.254602250","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","20.299605750","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","20.344609375","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","20.390862750","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","20.479621250","HID Input 1","01 00 00 2C 11 00 00 00 00" +"0","20.480871250","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","20.524623750","HID Input 1","01 00 00 11 18 00 00 00 00" +"0","20.569627750","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","20.614630625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","20.659633750","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","20.794646250","HID Input 1","01 00 00 10 05 00 00 00 00" +"0","20.839650500","HID Input 1","01 00 00 05 00 00 00 00 00" +"0","20.840900375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","20.929658125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","20.974661000","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","21.019666125","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","21.109672625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","21.110922625","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","21.199678625","HID Input 1","01 00 00 16 2C 00 00 00 00" +"0","21.244683250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","21.289683500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","21.334685625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","21.379689625","HID Input 1","01 00 00 17 12 00 00 00 00" +"0","21.424694000","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","21.425944125","HID Input 1","01 00 00 12 2C 00 00 00 00" +"0","21.514699625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","21.515949625","HID Input 1","01 00 00 2C 04 00 00 00 00" +"0","21.604709125","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","21.605959125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","21.694713500","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","21.784722750","HID Input 1","01 00 00 06 0E 00 00 00 00" +"0","21.785972625","HID Input 1","01 00 00 0E 00 00 00 00 00" +"0","21.829726625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","22.009742500","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","22.010992625","HID Input 1","01 00 00 11 12 00 00 00 00" +"0","22.054743875","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","22.144752500","HID Input 1","01 00 00 12 1A 00 00 00 00" +"0","22.146002500","HID Input 1","01 00 00 1A 00 00 00 00 00" +"0","22.189756125","HID Input 1","01 00 00 1A 08 00 00 00 00" +"0","22.191006125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","22.234757000","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","22.414772750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","22.416022875","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","22.549782750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","23.269841500","HID Input 1","01 00 00 0A 00 00 00 00 00" +"0","23.359849625","HID Input 1","01 00 00 0A 08 00 00 00 00" +"0","23.404853625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","23.494860375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","23.629872625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","23.764884000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","23.809888500","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","23.899893375","HID Input 1","01 00 00 17 0B 00 00 00 00" +"0","23.901143375","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","23.944895500","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","23.989898500","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","24.034901500","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","24.036151500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","24.079906625","HID Input 1","01 00 00 2C 15 00 00 00 00" +"0","24.169913375","HID Input 1","01 00 00 2C 15 08 00 00 00" +"0","24.171163250","HID Input 1","01 00 00 2C 08 00 00 00 00" +"0","24.214916375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","24.216166375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","24.259920750","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","24.394933000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","24.439935000","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","24.574946625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","24.619951625","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","24.754963125","HID Input 1","01 00 00 13 17 00 00 00 00" +"0","24.756213125","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","24.844968875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","24.979979750","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","25.024984125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","25.610031625","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","25.700039125","HID Input 1","01 00 00 12 09 00 00 00 00" +"0","25.745042375","HID Input 1","01 00 00 09 00 00 00 00 00" +"0","25.790047750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","25.880054250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","26.015066000","HID Input 1","01 00 00 2C 07 00 00 00 00" +"0","26.016316000","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","26.105073000","HID Input 1","01 00 00 07 04 00 00 00 00" +"0","26.150076625","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","26.240083250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","26.330091750","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","26.375095000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","26.465100250","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","26.555108125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","26.600111000","HID Input 1","01 00 00 37 00 00 00 00 00" +"0","26.690120000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","26.735123625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","26.825130625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","26.915137500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","26.960140750","HID Input 1","01 02 00 2C 00 00 00 00 00" +"0","27.005146375","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","27.095152500","HID Input 1","01 02 00 0C 00 00 00 00 00" +"0","27.140156250","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","27.185160250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","27.230164000","HID Input 1","01 00 00 09 00 00 00 00 00" +"0","27.275166750","HID Input 1","01 00 00 09 2C 00 00 00 00" +"0","27.276416875","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","27.365174625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","27.366424625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","27.410178500","HID Input 1","01 00 00 17 0B 00 00 00 00" +"0","27.455182125","HID Input 1","01 00 00 17 0B 08 00 00 00" +"0","27.456432125","HID Input 1","01 00 00 08 0B 00 00 00 00" +"0","27.500184375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","27.545187375","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","27.546437375","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","27.635196750","HID Input 1","01 00 00 2C 04 00 00 00 00" +"0","27.680197375","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","27.725198625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","27.815207125","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","27.860210750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","27.950218375","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","28.040226500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","28.085229750","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","28.220240875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","28.221490750","HID Input 1","01 00 00 0E 00 00 00 00 00" +"0","28.400254625","HID Input 1","01 00 00 0E 08 00 00 00 00" +"0","28.445259750","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","28.446509750","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","28.535264375","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","28.536514250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","28.580269250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","28.715280625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","28.716530750","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","28.805287875","HID Input 137","89 CA 52 04 12 00 00 00 00" +"0","28.850291125","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","28.851541125","HID Input 1","01 00 00 12 18 00 00 00 00" +"0","28.895294250","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","28.985298125","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","29.030302250","HID Input 1","01 00 00 0F 07 00 00 00 00" +"0","29.120309375","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","29.121559375","HID Input 1","01 00 00 07 2C 00 00 00 00" +"0","29.165310625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","29.210314625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","29.211564625","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","29.256569625","HID Input 1","01 00 00 13 15 00 00 00 00" +"0","29.300324125","HID Input 1","01 00 00 13 15 08 00 00 00" +"0","29.345327500","HID Input 1","01 00 00 13 08 00 00 00 00" +"0","29.390330125","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","29.391580000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","29.480336875","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","29.525340750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","29.570344125","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","29.615347125","HID Input 1","01 00 00 0C 06 00 00 00 00" +"0","29.705355375","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","29.706605375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","29.795362750","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","29.885371250","HID Input 1","01 00 00 17 2C 00 00 00 00" +"0","29.886621250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","29.975376500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","30.021631000","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","30.065381000","HID Input 1","01 00 00 17 0B 00 00 00 00" +"0","30.066631000","HID Input 1","01 00 00 17 0B 08 00 00 00" +"0","30.110383625","HID Input 1","01 00 00 08 0B 00 00 00 00" +"0","30.111633625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","30.155388250","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","30.156638250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","30.290395125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","30.650425125","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","30.740433125","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","30.741683125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","30.830439500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","30.875442375","HID Input 1","01 00 00 14 00 00 00 00 00" +"0","30.965450250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","30.966700250","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","31.055458375","HID Input 1","01 00 00 18 08 00 00 00 00" +"0","31.056708375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","31.100461875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","31.190469125","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","31.235472500","HID Input 1","01 00 00 11 06 00 00 00 00" +"0","31.236722375","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","31.280477250","HID Input 1","01 00 00 06 08 00 00 00 00" +"0","31.325481000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","31.326731000","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","31.370482500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","31.460490375","HID Input 1","01 00 00 2C 11 00 00 00 00" +"0","31.461740375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","31.550493750","HID Input 1","01 00 00 11 18 00 00 00 00" +"0","31.595498000","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","31.640501250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","31.685504375","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","31.820516875","HID Input 1","01 00 00 10 05 00 00 00 00" +"0","31.865519750","HID Input 1","01 00 00 05 00 00 00 00 00" +"0","31.866769750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","31.955528625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","32.000532625","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","32.090540250","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","32.091790000","HID Input 1","01 00 00 15 2C 00 00 00 00" +"0","32.135542000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","32.180545000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","32.225548750","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","32.270553125","HID Input 1","01 00 00 12 09 00 00 00 00" +"0","32.315557250","HID Input 1","01 00 00 12 09 2C 00 00 00" +"0","32.360559375","HID Input 1","01 00 00 12 2C 00 00 00 00" +"0","32.361809375","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","32.450569375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","32.451819250","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","32.495570750","HID Input 1","01 00 00 17 0B 00 00 00 00" +"0","32.540573375","HID Input 1","01 00 00 17 0B 08 00 00 00" +"0","32.541823375","HID Input 1","01 00 00 08 0B 00 00 00 00" +"0","32.585578375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","32.586828500","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","32.630580250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","32.675584750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","32.765592000","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","32.810591375","HID Input 1","01 00 00 13 04 00 00 00 00" +"0","32.900599250","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","32.901849250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","32.945604375","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","32.990608125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","33.035611125","HID Input 1","01 00 00 0E 00 00 00 00 00" +"0","33.125619250","HID Input 1","01 00 00 0E 08 00 00 00 00" +"0","33.170623500","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","33.171873500","HID Input 1","01 00 00 08 17 00 00 00 00" +"0","33.215623875","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","33.260627625","HID Input 1","01 00 00 17 2C 00 00 00 00" +"0","33.261877625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","33.395640500","HID Input 1","01 00 00 2C 05 00 00 00 00" +"0","33.396890500","HID Input 1","01 00 00 05 00 00 00 00 00" +"0","33.440643625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","33.485647375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","33.575654500","HID Input 1","01 00 00 08 0C 00 00 00 00" +"0","33.576904375","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","33.620658000","HID Input 1","01 00 00 0C 11 00 00 00 00" +"0","33.665661500","HID Input 1","01 00 00 0C 11 0A 00 00 00" +"0","33.666911500","HID Input 1","01 00 00 0A 11 00 00 00 00" +"0","33.755668250","HID Input 1","01 00 00 0A 00 00 00 00 00" +"0","33.756918125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","33.800673125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","33.845676250","HID Input 1","01 00 00 2C 16 00 00 00 00" +"0","33.890680625","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","33.935684125","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","33.980687375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","34.025691500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","34.026941500","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","34.115695000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","34.116945000","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","34.205701875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","34.206951875","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","34.295709250","HID Input 1","01 00 00 2C 09 00 00 00 00" +"0","34.340712875","HID Input 1","01 00 00 09 00 00 00 00 00" +"0","34.385717250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","34.430721000","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","34.520728875","HID Input 1","01 00 00 15 12 00 00 00 00" +"0","34.521978750","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","34.565731750","HID Input 1","01 00 00 12 10 00 00 00 00" +"0","34.610734500","HID Input 1","01 00 00 12 10 2C 00 00 00" +"0","34.700742750","HID Input 1","01 00 00 12 2C 00 00 00 00" +"0","34.701992750","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","34.745747375","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","34.746997375","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","34.790748375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","34.791998250","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","34.835752125","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","34.925760250","HID Input 1","01 00 00 0B 08 2C 00 00 00" +"0","34.927010125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","35.060771625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.062021500","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","35.105775000","HID Input 1","01 00 00 00 70 20 06 2C 00" +"0","35.195782250","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","35.285790375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.330794375","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","35.375792625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.465801500","HID Input 1","01 00 00 0A 00 00 00 00 00" +"0","35.555808750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.600812000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","35.645815375","HID Input 1","01 00 00 08 17 00 00 00 00" +"0","35.690818625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","35.735823875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.737074000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","35.825830875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.870835125","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","35.915839250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","35.960841500","HID Input 1","01 00 00 1C 00 00 00 00 00" +"0","36.005846000","HID Input 1","01 00 00 1C 16 00 00 00 00" +"0","36.050850500","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","36.095853625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","36.140856625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","36.230864750","HID Input 1","01 00 00 17 08 00 00 00 00" +"0","36.232114750","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","36.275867250","HID Input 1","01 00 00 08 10 00 00 00 00" +"0","36.320869875","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","36.365874125","HID Input 1","01 00 00 10 2C 00 00 00 00" +"0","36.410877625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","36.500885125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","36.502135125","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","36.545889500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","36.590893875","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","36.635894625","HID Input 1","01 00 00 12 2C 00 00 00 00" +"0","36.680895625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","36.682145625","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","36.725899500","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","36.770904625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","36.815908250","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","36.860910750","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","36.905914625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","36.907164500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","36.950917500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","36.995921250","HID Input 1","01 00 00 2C 15 00 00 00 00" +"0","37.040924750","HID Input 1","01 00 00 2C 15 08 00 00 00" +"0","37.085929000","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","37.087179000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","37.130933125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","37.220940750","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","37.265944250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","37.310947000","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","37.355951750","HID Input 1","01 00 00 0F 2C 00 00 00 00" +"0","37.445958625","HID Input 1","01 00 00 0F 2C 16 00 00 00" +"0","37.447208625","HID Input 1","01 00 00 16 2C 00 00 00 00" +"0","37.490961375","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","37.535965375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","37.580968750","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","37.625971750","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","37.670975375","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","37.672225500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","37.760984625","HID Input 1","01 00 00 19 00 00 00 00 00" +"0","37.805989000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","37.850992125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","37.940995250","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","37.985997750","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","37.987247625","HID Input 1","01 00 00 15 2C 00 00 00 00" +"0","38.031002125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","38.121009750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","38.122259750","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","38.166013250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","38.167263250","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","38.256020625","HID Input 1","01 00 00 18 15 00 00 00 00" +"0","38.302274625","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","38.346028500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","38.391031375","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","38.436035125","HID Input 1","01 00 00 0C 11 00 00 00 00" +"0","38.481040125","HID Input 1","01 00 00 0C 11 0A 00 00 00" +"0","38.482290125","HID Input 1","01 00 00 0C 11 0A 2C 00 00" +"0","38.526041625","HID Input 1","01 00 00 0C 11 2C 00 00 00" +"0","38.527291500","HID Input 1","01 00 00 2C 11 00 00 00 00" +"0","38.571045500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","38.616049125","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","38.617299125","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","38.661052375","HID Input 1","01 00 00 17 0B 00 00 00 00" +"0","38.706055375","HID Input 1","01 00 00 17 0B 08 00 00 00" +"0","38.707306500","HID Input 1","01 00 00 08 0B 00 00 00 00" +"0","38.751058750","HID Input 1","01 00 00 08 0B 2C 00 00 00" +"0","38.796062750","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","38.797312875","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","38.886069250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","38.931073625","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","38.976077250","HID Input 1","01 00 00 0C 11 00 00 00 00" +"0","39.066085000","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","39.156092000","HID Input 1","01 00 00 11 0C 00 00 00 00" +"0","39.157342000","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","39.246096250","HID Input 1","01 00 00 0C 17 00 00 00 00" +"0","39.247346125","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","39.291099375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","39.336103000","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","39.426111000","HID Input 1","01 00 00 0C 04 00 00 00 00" +"0","39.427361000","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","39.516119250","HID Input 1","01 00 00 04 0F 00 00 00 00" +"0","39.517369250","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","39.606125250","HID Input 1","01 00 00 0F 2C 00 00 00 00" +"0","39.607375250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","39.651128500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","39.741136750","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","39.831143875","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","39.876147375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","39.921152375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","39.966155750","HID Input 1","01 00 00 11 07 00 00 00 00" +"0","40.056163750","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","40.057413750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","40.146169625","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","40.236177500","HID Input 1","01 00 00 16 0B 00 00 00 00" +"0","40.237427500","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","40.327434250","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","40.461194250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","40.506195750","HID Input 1","01 00 00 0E 00 00 00 00 00" +"0","40.597453125","HID Input 1","01 00 00 0E 08 00 00 00 00" +"0","40.641202375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","40.731211125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","40.866222125","HID Input 1","01 00 00 36 00 00 00 00 00" +"0","40.956230125","HID Input 1","01 00 00 36 2C 00 00 00 00" +"0","41.001234000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","41.091241000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","41.226251750","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","41.316260625","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","41.317510625","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","41.361262875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","41.406265375","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","41.496272500","HID Input 1","01 00 00 2C 06 00 00 00 00" +"0","41.497522625","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","41.541277000","HID Input 1","01 00 00 06 12 00 00 00 00" +"0","41.586280625","HID Input 1","01 00 00 06 12 18 00 00 00" +"0","41.587530750","HID Input 1","01 00 00 18 12 00 00 00 00" +"0","41.631283125","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","41.721291500","HID Input 1","01 00 00 18 0F 00 00 00 00" +"0","41.722541500","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","41.766292625","HID Input 1","01 00 00 0F 07 00 00 00 00" +"0","41.811293250","HID Input 1","01 00 00 0F 07 2C 00 00 00" +"0","41.812543250","HID Input 1","01 00 00 0F 2C 00 00 00 00" +"0","41.856297750","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","41.946305125","HID Input 1","01 00 00 2C 06 00 00 00 00" +"0","41.947555125","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","42.037562000","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","42.081317000","HID Input 1","01 00 00 12 10 00 00 00 00" +"0","42.171324125","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","42.216328625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","42.261330625","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","42.351339750","HID Input 1","01 00 00 13 0F 00 00 00 00" +"0","42.396343375","HID Input 1","01 00 00 13 0F 08 00 00 00" +"0","42.441346125","HID Input 1","01 00 00 08 0F 00 00 00 00" +"0","42.486349500","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","42.487599500","HID Input 1","01 00 00 08 17 00 00 00 00" +"0","42.531352875","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","42.576356000","HID Input 1","01 00 00 17 08 00 00 00 00" +"0","42.621359000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","42.666363000","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","42.711367125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","42.756371250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","42.757621250","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","42.801376000","HID Input 1","01 00 00 17 0B 00 00 00 00" +"0","42.891383500","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","42.892633500","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","42.936384375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","42.937634250","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","42.981389000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","43.071391375","HID Input 1","01 00 00 2C 13 00 00 00 00" +"0","43.072641375","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","43.161397250","HID Input 1","01 00 00 13 15 00 00 00 00" +"0","43.162647250","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","43.206403125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","43.251407000","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","43.296409250","HID Input 1","01 00 00 12 06 00 00 00 00" +"0","43.386418125","HID Input 1","01 00 00 01 01 01 01 01 01" +"0","43.521429125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","43.522679000","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","43.611434875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","43.701442750","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","43.746447250","HID Input 1","01 00 00 16 2C 00 00 00 00" +"0","43.791449250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","43.881458500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","43.926462125","HID Input 1","01 00 00 05 00 00 00 00 00" +"0","43.971464750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","43.972714875","HID Input 1","01 00 00 1C 00 00 00 00 00" +"0","44.061472625","HID Input 1","01 00 00 1C 2C 00 00 00 00" +"0","44.106478000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","44.151481875","HID Input 1","01 00 00 2C 16 00 00 00 00" +"0","44.197735250","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","44.241489250","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","44.242739250","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","44.286490000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","44.331490375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","44.376494750","HID Input 1","01 00 00 11 07 00 00 00 00" +"0","44.421498625","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","44.466501000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","44.511505000","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","44.556509375","HID Input 1","01 00 00 0C 11 00 00 00 00" +"0","44.646516375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","44.691520375","HID Input 1","01 00 00 11 0A 00 00 00 00" +"0","44.692770500","HID Input 1","01 00 00 0A 00 00 00 00 00" +"0","44.736524875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","44.826532500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","44.961543750","HID Input 1","01 00 00 2C 04 00 00 00 00" +"0","44.962793625","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","45.096553625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","45.097803625","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","45.186561250","HID Input 1","01 00 00 11 2C 00 00 00 00" +"0","45.231566000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","45.232815875","HID Input 1","01 00 00 2C 04 00 00 00 00" +"0","45.276568500","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","45.321572375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","45.411580125","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","45.501587625","HID Input 1","01 00 00 06 0E 00 00 00 00" +"0","45.502837625","HID Input 1","01 00 00 0E 00 00 00 00 00" +"0","45.546591000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","45.681598375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","45.771605625","HID Input 1","01 00 00 11 12 00 00 00 00" +"0","45.816608750","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","45.861612250","HID Input 1","01 00 00 1A 00 00 00 00 00" +"0","45.951621250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","45.996624125","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","46.041626750","HID Input 1","01 00 00 0F 08 00 00 00 00" +"0","46.086630500","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","46.131635875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","46.176639250","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","46.266646625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","46.356654375","HID Input 1","01 00 00 0A 00 00 00 00 00" +"0","46.446661000","HID Input 1","01 00 00 0A 08 00 00 00 00" +"0","46.491665000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","46.536668125","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","46.581671750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","46.626677000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","46.716683375","HID Input 1","01 00 00 08 11 00 00 00 00" +"0","46.717933375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","46.806691875","HID Input 1","01 00 00 11 17 00 00 00 00" +"0","46.807942000","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","46.896693500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","46.941697625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","47.031705000","HID Input 1","01 00 00 2C 13 00 00 00 00" +"0","47.032955125","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","47.121712625","HID Input 1","01 00 00 13 04 00 00 00 00" +"0","47.211720625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","47.257972500","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","47.346731500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","47.347981500","HID Input 1","01 00 00 0E 00 00 00 00 00" +"0","47.481743250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","47.482993250","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","47.526745000","HID Input 1","01 00 00 08 17 00 00 00 00" +"0","47.571747750","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","47.616752750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","47.618002625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","47.751763625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","47.753013625","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","47.841771250","HID Input 1","01 02 00 25 00 00 00 00 00" +"0","47.976783000","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","48.246801750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","48.606832750","HID Input 1","01 00 00 2A 00 00 00 00 00" +"0","48.786848750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","48.876855500","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","49.011866500","HID Input 1","01 02 00 26 00 00 00 00 00" +"0","49.146879125","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","49.236886750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","49.371897125","HID Input 1","01 00 00 1A 00 00 00 00 00" +"0","49.461902125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","49.506905750","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","49.551908500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","49.596913250","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","49.641917250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","49.686919375","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","49.731923125","HID Input 1","01 00 00 0B 2C 00 00 00 00" +"0","49.821930625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","49.823180750","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","49.866936000","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","49.911939750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","49.913189750","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","49.956941750","HID Input 1","01 00 00 0B 08 00 00 00 00" +"0","50.001945000","HID Input 1","01 00 00 0B 08 2C 00 00 00" +"0","50.003194750","HID Input 1","01 00 00 2C 08 00 00 00 00" +"0","50.046949875","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","50.136957125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","50.183211125","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","50.226962625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","50.271965625","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","50.361975125","HID Input 1","01 00 00 12 15 00 00 00 00" +"0","50.406978625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","50.541989125","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","50.543239125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","50.631998250","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","50.677001500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","50.767003000","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","50.857010125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","50.948268375","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","51.037021125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","51.038271125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","51.172032125","HID Input 1","01 00 00 2C 16 00 00 00 00" +"0","51.217036750","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","51.218286625","HID Input 1","01 00 00 16 08 00 00 00 00" +"0","51.262039000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","51.352046625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","51.397049375","HID Input 1","01 00 00 14 00 00 00 00 00" +"0","51.487058500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","51.532061875","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","51.577066000","HID Input 1","01 00 00 18 08 00 00 00 00" +"0","51.622069125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","51.667073000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","51.712076250","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","51.802084625","HID Input 1","01 00 00 11 06 00 00 00 00" +"0","51.847088000","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","51.892091125","HID Input 1","01 00 00 06 08 00 00 00 00" +"0","51.893341250","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","51.982098250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","51.983348375","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","52.072100750","HID Input 1","01 00 00 2C 11 00 00 00 00" +"0","52.117105250","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","52.162109125","HID Input 1","01 00 00 11 18 00 00 00 00" +"0","52.207111750","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","52.252116125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","52.342123375","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","52.432130625","HID Input 1","01 00 00 10 05 00 00 00 00" +"0","52.477135375","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","52.478385250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","52.567143250","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","52.612147125","HID Input 1","01 00 00 08 15 00 00 00 00" +"0","52.657151250","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","52.747158125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","52.837166000","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","53.467215875","HID Input 1","01 02 00 26 00 00 00 00 00" +"0","53.468465875","HID Input 1","01 02 00 26 27 00 00 00 00" +"0","53.512220250","HID Input 1","01 02 00 26 00 00 00 00 00" +"0","53.557222375","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","53.872250500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","54.007262250","HID Input 1","01 00 00 2A 00 00 00 00 00" +"0","54.142273375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","54.277285625","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","54.457299750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","54.502303750","HID Input 1","01 00 00 2A 00 00 00 00 00" +"0","54.637311625","HID Input 1","01 02 00 2A 00 00 00 00 00" +"0","54.638561625","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","54.773573375","HID Input 1","01 02 00 27 00 00 00 00 00" +"0","54.862331375","HID Input 1","01 02 00 00 00 00 00 00 00" +"0","55.042347000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","55.222360250","HID Input 1","01 00 00 36 00 00 00 00 00" +"0","55.312369125","HID Input 1","01 00 00 36 2C 00 00 00 00" +"0","55.402376500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","55.492384125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","55.493634125","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","55.582389375","HID Input 1","01 00 00 04 11 00 00 00 00" +"0","55.627393375","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","55.672398250","HID Input 1","01 00 00 11 07 00 00 00 00" +"0","55.673648250","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","55.762406250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","55.763656000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","55.942415000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","55.943665000","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","55.987417000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","56.077425250","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","56.167432250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","56.302444625","HID Unknown","" +"0","56.392451875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","56.437456375","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","56.527463625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","56.662474625","HID Input 1","01 00 00 05 00 00 00 00 00" +"0","56.707480000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","56.708729875","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","56.797485375","HID Input 1","01 00 00 0F 0C 00 00 00 00" +"0","56.842489625","HID Input 1","01 00 00 0F 00 00 00 00 00" +"0","56.887493250","HID Input 1","01 00 00 0F 16 00 00 00 00" +"0","56.888743250","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","56.977502000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","57.022503625","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","57.067507500","HID Input 1","01 00 00 0B 2C 00 00 00 00" +"0","57.112511500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","57.157510875","HID Input 1","01 00 00 2C 04 00 00 00 00" +"0","57.158760750","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","57.247519000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","57.292522125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","57.382531000","HID Input 1","01 00 00 2C 06 00 00 00 00" +"0","57.517541500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","57.518791500","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","57.607548750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","57.652552250","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","57.742559750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","57.832567250","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","57.877572375","HID Input 1","01 00 00 11 08 00 00 00 00" +"0","57.922575875","HID Input 1","01 00 00 11 00 00 00 00 00" +"0","57.967580250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","58.012583250","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","58.102590750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","58.192599000","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","58.282606625","HID Input 1","01 00 00 17 0C 00 00 00 00" +"0","58.327609125","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","58.372612500","HID Input 1","01 00 00 0C 12 00 00 00 00" +"0","58.373862500","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","58.462618125","HID Input 1","01 00 00 12 11 00 00 00 00" +"0","58.507622375","HID Input 1","01 00 00 12 11 2C 00 00 00" +"0","58.508872375","HID Input 1","01 00 00 2C 11 00 00 00 00" +"0","58.552624250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","58.597627500","HID Input 1","01 00 00 2C 04 00 00 00 00" +"0","58.642631250","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","58.687634750","HID Input 1","01 00 00 04 13 00 00 00 00" +"0","58.688884625","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","58.732638750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","58.822646125","HID Input 1","01 00 00 13 00 00 00 00 00" +"0","58.912654125","HID Input 1","01 00 00 13 08 00 00 00 00" +"0","59.002661500","HID Input 1","01 00 00 13 08 04 00 00 00" +"0","59.003911500","HID Input 1","01 00 00 13 04 00 00 00 00" +"0","59.047665000","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","59.092668625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","59.137671250","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","59.227679750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","59.272683500","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","59.407694500","HID Input 1","01 00 00 0C 11 0A 00 00 00" +"0","59.452698250","HID Input 1","01 00 00 0A 11 00 00 00 00" +"0","59.453948250","HID Input 1","01 00 00 0A 00 00 00 00 00" +"0","59.497703125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","59.498953125","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","59.632713000","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","59.633963000","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","59.722715250","HID Input 1","01 00 00 17 12 00 00 00 00" +"0","59.723965250","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","59.767718375","HID Input 1","01 00 00 12 2C 00 00 00 00" +"0","59.857727375","HID Input 1","01 00 00 12 2C 05 00 00 00" +"0","59.902730250","HID Input 1","01 00 00 05 2C 00 00 00 00" +"0","59.903980250","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","59.947732125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","59.992735500","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","60.037739000","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","60.082743625","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","60.172751000","HID Input 1","01 00 00 2C 09 00 00 00 00" +"0","60.174001000","HID Input 1","01 00 00 09 00 00 00 00 00" +"0","60.262759500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","60.307763625","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","60.397771000","HID Input 1","01 00 00 15 12 00 00 00 00" +"0","60.399021000","HID Input 1","01 00 00 12 00 00 00 00 00" +"0","60.442772250","HID Input 1","01 00 00 12 10 00 00 00 00" +"0","60.487776000","HID Input 1","01 00 00 12 10 2C 00 00 00" +"0","60.577784000","HID Input 1","01 00 00 12 2C 00 00 00 00" +"0","60.579033875","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","60.622788500","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","60.624038625","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","60.667791250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","60.712794375","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","60.714044500","HID Input 1","01 00 00 08 0B 00 00 00 00" +"0","60.802801875","HID Input 1","01 00 00 08 0B 2C 00 00 00" +"0","60.804052000","HID Input 1","01 00 00 08 2C 00 00 00 00" +"0","60.847804000","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","60.937812125","HID Input 1","01 00 00 2C 17 00 00 00 00" +"0","60.939062375","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","60.982813125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","61.072820000","HID Input 1","01 00 00 15 00 00 00 00 00" +"0","61.162828125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","61.207832375","HID Input 1","01 00 00 18 00 00 00 00 00" +"0","61.252834500","HID Input 1","01 00 00 18 16 00 00 00 00" +"0","61.344092625","HID Input 1","01 00 00 16 00 00 00 00 00" +"0","61.387843500","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","61.432846875","HID Input 1","01 00 00 17 00 00 00 00 00" +"0","61.522854875","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","61.567857750","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","61.657865625","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","61.702869375","HID Input 1","01 00 00 07 00 00 00 00 00" +"0","61.837880125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","62.332919500","HID Input 1","01 00 00 2C 00 00 00 00 00" +"0","62.422927500","HID Input 1","01 00 00 2C 10 00 00 00 00" +"0","62.424177500","HID Input 1","01 00 00 10 00 00 00 00 00" +"0","62.557937875","HID Input 1","01 00 00 10 04 00 00 00 00" +"0","62.602940875","HID Input 1","01 00 00 04 00 00 00 00 00" +"0","62.604190750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","62.692948750","HID Input 1","01 00 00 06 00 00 00 00 00" +"0","62.737952750","HID Input 1","01 00 00 06 0B 00 00 00 00" +"0","62.782957500","HID Input 1","01 00 00 0B 00 00 00 00 00" +"0","62.872964375","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","62.874214250","HID Input 1","01 00 00 0C 00 00 00 00 00" +"0","62.962971250","HID Input 1","01 00 00 0C 11 00 00 00 00" +"0","63.007974750","HID Input 1","01 00 00 0C 11 08 00 00 00" +"0","63.052978125","HID Input 1","01 00 00 08 11 00 00 00 00" +"0","63.054228125","HID Input 1","01 00 00 08 00 00 00 00 00" +"0","63.097981750","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","63.187990000","HID Input 1","01 00 00 37 00 00 00 00 00" +"0","63.323001250","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","63.593020125","HID Input 1","01 00 00 28 00 00 00 00 00" +"0","63.683028125","HID Input 1","01 00 00 00 00 00 00 00 00" +"0","63.773035125","HID Input 1","01 00 00 28 00 00 00 00 00" +"0","63.818038625","HID Input 1","01 00 00 00 00 00 00 00 00" diff --git a/libbtbb-2015-10-R1/python/utils/encode_sw.py b/libbtbb-2015-10-R1/python/utils/encode_sw.py new file mode 100755 index 0000000..6583abf --- /dev/null +++ b/libbtbb-2015-10-R1/python/utils/encode_sw.py @@ -0,0 +1,67 @@ +#!/usr/bin/python + +# produce a sync word for a given LAP + +lap = 0xffffff + +pn = 0x83848D96BBCC54FC + +# generator matrix for (64,30) linear block code +# based on polynomial 0260534236651 +# (see gen_check_tables.py for automatic generation) +g = ( + 0x8000000000000001, + 0x40000002c2b89ed4, + 0x20000001615c4f6a, + 0x10000000b0ae27b5, + 0x080000029aef8d0e, + 0x040000014d77c687, + 0x0200000264037d97, + 0x01000003f0b9201f, + 0x008000033ae40edb, + 0x004000035fca99b9, + 0x002000036d5dd208, + 0x00100001b6aee904, + 0x00080000db577482, + 0x000400006dabba41, + 0x00020002f46d43f4, + 0x000100017a36a1fa, + 0x00008000bd1b50fd, + 0x000040029c3536aa, + 0x000020014e1a9b55, + 0x0000100265b5d37e, + 0x0000080132dae9bf, + 0x000004025bd5ea0b, + 0x00000203ef526bd1, + 0x000001033511ab3c, + 0x000000819a88d59e, + 0x00000040cd446acf, + 0x00000022a41aabb3, + 0x0000001390b5cb0d, + 0x0000000b0ae27b52, + 0x0000000585713da9) + +def encode(data): + assert data < 2**30 + codeword = 0 + for i in range(30): + if (data & (0x20000000 >> i)): + codeword ^= g[i] + return codeword + +# append barker code +if (lap & 0x800000): + data = 0x13000000 | lap +else: + data = 0x2c000000 | lap + +# scramble +data ^= (pn >> 34) + +# encode +codeword = encode(data) + +# scramble again +syncword = codeword ^ pn + +print "0x%06x 0x%016x 0x%016x" % (lap, codeword, syncword) diff --git a/libbtbb-2015-10-R1/python/utils/gen_barker_correct.py b/libbtbb-2015-10-R1/python/utils/gen_barker_correct.py new file mode 100755 index 0000000..f428def --- /dev/null +++ b/libbtbb-2015-10-R1/python/utils/gen_barker_correct.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +# Reverse the binary of thesebarker codes for the host code +barkers = (0x0d, 0x72) +distances = [] +corrections = [] + +def count_bits(x): + i = 0 + while x: + i += 1 + x &= x - 1 + return i + +for i in range(128): + diffs = [(count_bits(barkers[0] ^ i), barkers[0]), + (count_bits(barkers[1] ^ i), barkers[1])] + diffs.sort() + distances.append(diffs[0][0]) + corrections.append(diffs[0][1]) + +print "Barker distance:", distances +print "Barker correct:", ["0x%x" % c for c in corrections] diff --git a/libbtbb-2015-10-R1/python/utils/gen_check_tables.py b/libbtbb-2015-10-R1/python/utils/gen_check_tables.py new file mode 100755 index 0000000..0ae41df --- /dev/null +++ b/libbtbb-2015-10-R1/python/utils/gen_check_tables.py @@ -0,0 +1,59 @@ +#!/usr/bin/python + +# (64,30) linear block code stuff + +polynomial = 0260534236651 + +# produce generator matrix g +g = [] +for i in range(30): + g.append(polynomial << i) + for j in range(i): + if g[i] & (1 << (33 + i - j)): + g[i] ^= g[i-j-1] + +#print +#for i in range(29,-1,-1): + #print "0x%016x," % g[i] +#print + +# produce check matrix h +h = [] +for i in range(34): + h.append(0) + for j in range(30): + h[i] |= (g[29-j] >> i) & 0x1 + h[i] <<= 1 + h[i] <<= 33 + h[i] |= (0x1 << i) + +#print +#for i in range(34): + #print "0x%016x," % h[i] +#print + +# reverse the order +g = g[::-1] +h = h[::-1] + +def count_bits(n): + i = 0 + while n != 0: + n &= n - 1 + i += 1 + return i + +def gen_syndrome(c): + assert c < 2**64 + s = 0 + # look for a faster GF(2) matrix multiplication algorithm + for i in range(34): + s <<= 1 + s |= (count_bits(c & h[i]) % 2) + return s + +# optimized check table generation (sw_check_tables.h) +for shift in range(8): + for i in range(256): + print "0x%09x, " % gen_syndrome(i<<(shift*8)), + print diff --git a/libbtbb-2015-10-R1/python/utils/le_whitening.py b/libbtbb-2015-10-R1/python/utils/le_whitening.py new file mode 100755 index 0000000..6ce9a9b --- /dev/null +++ b/libbtbb-2015-10-R1/python/utils/le_whitening.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +num_channels = 40 +bits = [] +channels = {} +reg = 0x57 + +while not (len(bits) and reg==0x57): + if reg & 0x3f < num_channels and reg & 0x40: + channels[reg & 0x3f] = len(bits) + bit = (reg & 1) + bits.append(bit) + reg >>= 1 + reg |= (bit << 6) + reg ^= (bit << 2) + +print bits + +print "\nArray index:" +for k in sorted(channels.keys()): + print channels[k] diff --git a/libbtbb-2015-10-R1/tests/Makefile b/libbtbb-2015-10-R1/tests/Makefile new file mode 100644 index 0000000..b0f16ac --- /dev/null +++ b/libbtbb-2015-10-R1/tests/Makefile @@ -0,0 +1,36 @@ +# Copyright 2011 Michael Ossmann, Dominic Spill +# +# This file is part of Project Ubertooth. +# +# 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, 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +CC ?= gcc + +SOURCE_FILES = test_syndromes.c +LIBRARY_SOURCE = ../bluetooth_packet.c +BINARY_FILES = test_syndromes +HEADER_FILES = ../bluetooth_packet.h + +CFLAGS += -DHASH_FUNCTION=HASH_FNV -DHASH_EMIT_KEYS=3 + +all: test_packet + +test_packet: + $(CC) $(CFLAGS) $(CPPFLAGS) -O2 -Wall $(LIBRARY_SOURCE) $(SOURCE_FILES) -o $(BINARY_FILES) + +clean: + rm -f $(BINARY_FILES) + diff --git a/libbtbb-2015-10-R1/tests/test_fec23.c b/libbtbb-2015-10-R1/tests/test_fec23.c new file mode 100644 index 0000000..d886a44 --- /dev/null +++ b/libbtbb-2015-10-R1/tests/test_fec23.c @@ -0,0 +1,122 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2011 Dominic Spill, Michael Ossmann + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../bluetooth_packet.h" +#include + +int test_unfec23() { + char *optr; + int i, j, ret, err; + ret = 0; + + printf("Testing unfec23\n"); + printf("---------------\n"); + + char input[20][15] = { + /* No errors */ + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0}, + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, + {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0}, + {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, + {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1}, + /* Errors */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1} + }; + + char output[20][15] = { + /* No errors */ + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + /* Errors */ + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + }; + + for(i = 0; i < 20; i++) { + if (optr = unfec23(input[i], 1)) { + err = 0; + for(j = 0; j < 10; j++) { + if (optr[j] != output[i][j]) { + err = 1; + break; + } + } + if (err == 1) { + printf("E"); + ret++; + } + else + printf("."); + } else { + printf("F"); + ret++; + } + } + + if (ret > 0) + printf("%d errors\n", ret); + printf("\n--------------------\n"); + printf("Done testing unfec23\n"); + return ret; +} + +int main(int argc, char** argv) { + int ret = 0; + + ret += test_unfec23(); + + exit(ret); +} diff --git a/libbtbb-2015-10-R1/tests/test_header.c b/libbtbb-2015-10-R1/tests/test_header.c new file mode 100644 index 0000000..4988103 --- /dev/null +++ b/libbtbb-2015-10-R1/tests/test_header.c @@ -0,0 +1,118 @@ +/* -*- c -*- */ +/* + * Copyright 2012 Dominic Spill + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +/* +UAP Data HEC Header (octal) +---------------------------------- +00 123 e1 770007 007070 000777 +47 123 06 770007 007007 700000 +00 124 32 007007 007007 007700 +47 124 d5 007007 007070 707077 +00 125 5a 707007 007007 077070 +47 125 bd 707007 007070 777707 +00 126 e2 077007 007007 000777 +47 126 05 077007 007070 700000 +00 127 8a 777007 007007 070007 +47 127 6d 777007 007070 770770 +00 11b 9e 770770 007007 777007 +47 11b 79 770770 007070 077770 +00 11c 4d 007770 007070 770070 +47 11c aa 007770 007007 070707 +00 11d 25 707770 007070 700700 +47 11d c2 707770 007007 000077 +00 11e 9d 077770 007070 777007 +47 11e 7a 077770 007007 077770 +00 11f f5 777770 007070 707777 +47 11f 12 777770 007007 007000 +*/ + +#include "../bluetooth_packet_tx.h" +#include + +int test_gen_packet_header() { + char *optr; + int i, j, ret, err; + ret = 0; + + printf("Testing header\n"); + printf("---------------\n"); + + /* lt_addr, type, flow, arqn, seqn, UAP, HEC */ + uint8_t data[20][7] = { + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + UAP Data HE + ----------- + 00 123 e1 + 47 123 06 + 00 124 32 + 47 124 d5 + 00 125 5a + 47 125 bd + 00 126 e2 + 47 126 05 + 00 127 8a + 47 127 6d + 00 11b 9e + 47 11b 79 + 00 11c 4d + 47 11c aa + 00 11d 25 + 47 11d c2 + 00 11e 9d + 47 11e 7a + 00 11f f5 + 47 11f 12 + + }; + + for(i = 0; i < 20; i++) { + gen_packet_header(uint8_t lt_addr, uint8_t type, uint8_t flow, uint8_t arqn, uint8_t seqn) + if (uap == 1) { + printf("E"); + ret++; + } + else + printf("."); + } + + if (ret > 0) + printf("%d errors\n", ret); + printf("\n--------------------\n"); + printf("Done testing unfec23\n"); + return ret; +} + +int main(int argc, char** argv) { + int ret = 0; + + ret += test_unfec23(); + + exit(ret); +} diff --git a/libbtbb-2015-10-R1/tests/test_syndromes.c b/libbtbb-2015-10-R1/tests/test_syndromes.c new file mode 100644 index 0000000..300a328 --- /dev/null +++ b/libbtbb-2015-10-R1/tests/test_syndromes.c @@ -0,0 +1,100 @@ +/* -*- c -*- */ +/* + * Copyright 2007 - 2011 Dominic Spill, Michael Ossmann + * + * This file is part of libbtbb + * + * 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, 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 libbtbb; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../bluetooth_packet.h" +#include + +int test_syndromes() { + int ret, i; + uint64_t syndrome, syncword; + ret = 0; + + printf("Testing syndromes\n"); + printf("-----------------\n"); + + uint64_t syndrome_input[2] = { + /* No errors */ + 0xcc7b7268ff614e1b, + /* Errors */ + 0xcc7d7268ff614e1b + }; + + uint64_t syndrome_output[2] = { + /* No errors */ + 0, + /* Errors */ + 0x0000000299c6f9b5 + }; + + for(i = 0; i < 2; i++) { + syndrome = gen_syndrome(syndrome_input[i]); + if (syndrome == syndrome_output[i]) { + printf("."); + } else { + printf("F"); + ret++; + } + } + + uint64_t syncword_input[2] = { + /* No errors */ + 0xcc7b7268ff614e1b, + /* Errors */ + 0xcc7b7268ff514e1b + }; + + uint64_t syncword_output[2] = { + /* No errors */ + 0x4ffffffe44ad1ae7, + /* Errors */ + 0x4ffffffe44ad1ae7 + }; + + gen_syndrome_map(); + for(i = 0; i < 2; i++) { + syncword = decode_syncword(syncword_input[i] ^ pn); + if (syncword == syncword_output[i]) { + printf("."); + } else { + printf("F"); + ret++; + } + } + + if (ret > 0) + printf("%d errors\n", ret); + printf("\n-----------------\n"); + printf("Done testing syndrome generation\n"); + return ret; +} + +int main(int argc, char** argv) { + int ret = 0; + + ret += test_syndromes(); + + exit(ret); +} diff --git a/libbtbb-2015-10-R1/web/index.html b/libbtbb-2015-10-R1/web/index.html new file mode 100644 index 0000000..37e8af6 --- /dev/null +++ b/libbtbb-2015-10-R1/web/index.html @@ -0,0 +1,40 @@ + + + + +Libbtbb - Bluetooth baseband library + + +

Libbtbb - Bluetooth baseband library

+

Libbtbb is the Bluetooth baseband library used by the Ubertooth and +gr-bluetooth projects. It is freely available under the +GPL v2 license.

+ +

Getting libbtbb

+

Libbtbb is built from source using either a released archive or the latest +code from our git repository. +To get started, do either of the following:

+
    +
  • +Download the latest release
  • +
  • or clone the git repository using the following command: +
    git clone https://github.com/greatscottgadgets/libbtbb.git
  • +
  • If you prefer to use ssh and have a GitHub +account, you can use this command: +
    git clone git@github.com:greatscottgadgets/libbtbb.git
  • +
+ +

Support

+

Support for libbtbb is provided by +project Ubertooth, either using +the +mailing list or via IRC in #ubertooth on +chat.freenode.net

+

Bugs may be reported and tracked in the +ticketing system. +Although it often helps to mention the bug report on the + +Ubertooth mailing list to be sure that it has been seen.

+ + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/AUTHORS b/libbtbb-2015-10-R1/wireshark/plugins/btatt/AUTHORS new file mode 100644 index 0000000..b0e215f --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/AUTHORS @@ -0,0 +1,5 @@ +Authors: +Allan M. Madsen + +Converted to plugin by: +Mike Ryan diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/CMakeLists.txt b/libbtbb-2015-10-R1/wireshark/plugins/btatt/CMakeLists.txt new file mode 100644 index 0000000..078c838 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/CMakeLists.txt @@ -0,0 +1,88 @@ +# CMakeLists.txt +# +# $Id: CMakeLists.txt 31995 2010-02-24 22:32:10Z jmayer $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +project(btatt-wireshark-plugin C) + +cmake_minimum_required(VERSION 2.6) +set(CMAKE_BACKWARDS_COMPATIBILITY 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +IF ( NOT CMAKE_INSTALL_LIBDIR ) + set(CMAKE_INSTALL_LIBDIR ~/.wireshark/plugins) +ENDIF ( NOT CMAKE_INSTALL_LIBDIR ) +MESSAGE (STATUS "Plugin will be installed in: ${CMAKE_INSTALL_LIBDIR}") + +INCLUDE(UseMakeDissectorReg) + +set(GLIB2_MIN_VERSION 2.4.0) + +find_package(GLIB2) +include_directories (${GLIB2_INCLUDE_DIRS}) + +find_package(Wireshark) +include_directories (${WIRESHARK_INCLUDE_DIRS}) + +set(LINK_MODE_LIB SHARED) +set(LINK_MODE_MODULE MODULE) + + +set(DISSECTOR_SRC + packet-btatt.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} +) + +set(CLEAN_FILES + ${PLUGIN_FILES} +) + +if (WERROR) + set_source_files_properties( + ${CLEAN_FILES} + PROPERTIES + COMPILE_FLAGS -Werror + ) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +register_dissector_files(plugin.c + plugin + ${DISSECTOR_SRC} +) + +add_library(btatt ${LINK_MODE_MODULE} + ${PLUGIN_FILES} +) +set_target_properties(btatt PROPERTIES PREFIX "") +set_target_properties(btatt PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}") + +target_link_libraries(btatt wireshark) + +install(TARGETS btatt + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/ NAMELINK_SKIP +) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btatt/COPYING new file mode 100644 index 0000000..aa0aea5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.am b/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.am new file mode 100644 index 0000000..d379428 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.am @@ -0,0 +1,125 @@ +# Makefile.am +# Automake file for AgentX plugin +# +# $Id: Makefile.am 24488 2008-02-27 16:18:30Z stig $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +INCLUDES = -I$(top_srcdir) -I$(includedir) + +include Makefile.common + +#if HAVE_WARNINGS_AS_ERRORS +#AM_CFLAGS = -Werror +#endif + +plugindir = @plugindir@ + +plugin_LTLIBRARIES = btatt.la +btatt_la_SOURCES = \ + plugin.c \ + moduleinfo.h \ + $(DISSECTOR_SRC) \ + $(DISSECTOR_SUPPORT_SRC) \ + $(DISSECTOR_INCLUDES) +btatt_la_LDFLAGS = -module -avoid-version +btatt_la_LIBADD = @PLUGIN_LIBS@ + +# Libs must be cleared, or else libtool won't create a shared module. +# If your module needs to be linked against any particular libraries, +# add them here. +LIBS = + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ + $(top_srcdir)/tools/make-dissector-reg.py + @if test -n "$(PYTHON)"; then \ + echo Making plugin.c with python ; \ + $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + plugin $(DISSECTOR_SRC) ; \ + else \ + echo Making plugin.c with shell script ; \ + $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + $(plugin_src) plugin $(DISSECTOR_SRC) ; \ + fi + +# +# Currently plugin.c can be included in the distribution because +# we always build all protocol dissectors. We used to have to check +# whether or not to build the snmp dissector. If we again need to +# variably build something, making plugin.c non-portable, uncomment +# the dist-hook line below. +# +# Oh, yuk. We don't want to include "plugin.c" in the distribution, as +# its contents depend on the configuration, and therefore we want it +# to be built when the first "make" is done; however, Automake insists +# on putting *all* source into the distribution. +# +# We work around this by having a "dist-hook" rule that deletes +# "plugin.c", so that "dist" won't pick it up. +# +#dist-hook: +# @rm -f $(distdir)/plugin.c + +CLEANFILES = \ + btatt \ + *~ + +MAINTAINERCLEANFILES = \ + Makefile.in \ + plugin.c + +EXTRA_DIST = \ + Makefile.common \ + Makefile.nmake \ + moduleinfo.nmake \ + plugin.rc.in diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.common b/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.common new file mode 100644 index 0000000..5dbd7c1 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.common @@ -0,0 +1,39 @@ +# Makefile.common for AgentX plugin +# Contains the stuff from Makefile.am and Makefile.nmake that is +# a) common to both files and +# b) portable between both files +# +# $Id: Makefile.common 23848 2007-12-12 22:10:50Z jake $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# the name of the plugin +PLUGIN_NAME = btatt + +# the dissector sources (without any helpers) +DISSECTOR_SRC = \ + packet-btatt.c + +# corresponding headers +DISSECTOR_INCLUDES = + +# Dissector helpers. They're included in the source files in this +# directory, but they're not dissectors themselves, i.e. they're not +# used to generate "plugin.c". +DISSECTOR_SUPPORT_SRC = diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.nmake b/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.nmake new file mode 100644 index 0000000..857e435 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/Makefile.nmake @@ -0,0 +1,100 @@ +# Makefile.nmake +# nmake file for Wireshark plugin +# +# $Id: Makefile.nmake 24520 2008-03-01 12:31:01Z jake $ +# + +include ..\..\config.nmake +include moduleinfo.nmake + +include Makefile.common + +CFLAGS=/WX /DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \ + /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS) + +.c.obj:: + $(CC) $(CFLAGS) -Fd.\ -c $< + +LDFLAGS = $(PLUGIN_LDFLAGS) + +!IFDEF ENABLE_LIBWIRESHARK +LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib +CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS) + +DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj) + +DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj) + +OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) plugin.obj + +RESOURCE=$(PLUGIN_NAME).res + +all: $(PLUGIN_NAME).dll + +$(PLUGIN_NAME).rc : moduleinfo.nmake + sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ \ + -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ \ + -e s/@RC_VERSION@/$(RC_VERSION)/ \ + -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ \ + -e s/@PACKAGE@/$(PACKAGE)/ \ + -e s/@VERSION@/$(VERSION)/ \ + -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ \ + < plugin.rc.in > $@ + +$(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE) + link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \ + $(GLIB_LIBS) $(RESOURCE) + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +!IFDEF PYTHON +plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg.py + @echo Making plugin.c (using python) + @$(PYTHON) "../../tools/make-dissector-reg.py" . plugin $(DISSECTOR_SRC) +!ELSE +plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg + @echo Making plugin.c (using sh) + @$(SH) ../../tools/make-dissector-reg . plugin $(DISSECTOR_SRC) +!ENDIF + +!ENDIF + +clean: + rm -f $(OBJECTS) $(RESOURCE) plugin.c *.pdb \ + $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib \ + $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc + +distclean: clean + +maintainer-clean: distclean diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/README b/libbtbb-2015-10-R1/wireshark/plugins/btatt/README new file mode 100644 index 0000000..97538d5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/README @@ -0,0 +1,11 @@ +Bluetooth ATT Protocol Dissector +================================ + +This is a plugin-ized version of the Bluetooth ATT protocol dissector +from the Wireshark trunk. I made the very minimal changes necessary to +get it to build as a plugin: defining a couple constants and changing an +include path. + +This plugin is unneccessary if you are using Wireshark trunk. Only use +it if you are using a distro packaged Wireshark that does not have btatt +protocol support. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING new file mode 100644 index 0000000..53b6b71 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING-CMAKE-SCRIPTS b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..280ed6c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,27 @@ +Copyright notice for the files copied from +http://www.opensync.org/browser/branches/3rd-party-cmake-modules/modules + +$Id: COPYING-CMAKE-SCRIPTS 34248 2010-09-25 15:38:12Z jmayer $ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindGLIB2.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindGLIB2.cmake new file mode 100644 index 0000000..ae7badd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindGLIB2.cmake @@ -0,0 +1,238 @@ +# +# $Id: FindGLIB2.cmake 34248 2010-09-25 15:38:12Z jmayer $ +# +# - Try to find GLib2 +# Once done this will define +# +# GLIB2_FOUND - system has GLib2 +# GLIB2_INCLUDE_DIRS - the GLib2 include directory +# GLIB2_LIBRARIES - Link these to use GLib2 +# +# HAVE_GLIB_GREGEX_H glib has gregex.h header and +# supports g_regex_match_simple +# +# Copyright (c) 2006 Andreas Schneider +# Copyright (c) 2006 Philippe Bernery +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Alban Browaeys +# Copyright (c) 2008 Michael Bell +# Copyright (c) 2008-2009 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +IF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + # in cache already + SET(GLIB2_FOUND TRUE) +ELSE (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + + INCLUDE(FindPkgConfig) + + ## Glib + IF ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) + ELSE ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) + ENDIF ( GLIB2_FIND_REQUIRED ) + + IF ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0>=${GLIB2_MIN_VERSION} ) + ELSE ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0 ) + ENDIF ( GLIB2_MIN_VERSION ) + IF ( PKG_CONFIG_FOUND ) + IF ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( GLIB2_FOUND ) + ENDIF ( PKG_CONFIG_FOUND ) + + # Look for glib2 include dir and libraries w/o pkgconfig + IF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( + _glibconfig_include_DIR + NAMES + glibconfig.h + PATHS + /opt/gnome/lib64 + /opt/gnome/lib + /opt/lib/ + /opt/local/lib + /sw/lib/ + /usr/lib64 + /usr/lib + /usr/local/include + ${CMAKE_LIBRARY_PATH} + PATH_SUFFIXES + glib-2.0/include + ) + + FIND_PATH( + _glib2_include_DIR + NAMES + glib.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + PATH_SUFFIXES + glib-2.0 + ) + + #MESSAGE(STATUS "Glib headers: ${_glib2_include_DIR}") + + FIND_LIBRARY( + _glib2_link_DIR + NAMES + glib-2.0 + glib + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + IF ( _glib2_include_DIR AND _glib2_link_DIR ) + SET ( _glib2_FOUND TRUE ) + ENDIF ( _glib2_include_DIR AND _glib2_link_DIR ) + + + IF ( _glib2_FOUND ) + SET ( GLIB2_INCLUDE_DIRS ${_glib2_include_DIR} ${_glibconfig_include_DIR} ) + SET ( GLIB2_LIBRARIES ${_glib2_link_DIR} ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( _glib2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( _glib2_FOUND ) + + # Handle dependencies + # libintl + IF ( NOT LIBINTL_FOUND ) + FIND_PATH(LIBINTL_INCLUDE_DIR + NAMES + libintl.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + ) + + FIND_LIBRARY(LIBINTL_LIBRARY + NAMES + intl + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/local/lib + /usr/lib + ) + + IF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + SET (LIBINTL_FOUND TRUE) + ENDIF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + ENDIF ( NOT LIBINTL_FOUND ) + + # libiconv + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR + NAMES + iconv.h + PATHS + /opt/gnome/include + /opt/local/include + /opt/local/include + /sw/include + /sw/include + /usr/local/include + /usr/include + PATH_SUFFIXES + glib-2.0 + ) + + FIND_LIBRARY(LIBICONV_LIBRARY + NAMES + iconv + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + + IF (LIBINTL_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBINTL_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBINTL_INCLUDE_DIR}) + ENDIF (LIBINTL_FOUND) + + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) + + ENDIF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + ## + + IF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + SET (GLIB2_FOUND TRUE) + ENDIF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + + IF (GLIB2_FOUND) + IF (NOT GLIB2_FIND_QUIETLY) + MESSAGE (STATUS "Found GLib2: ${GLIB2_LIBRARIES} ${GLIB2_INCLUDE_DIRS}") + ENDIF (NOT GLIB2_FIND_QUIETLY) + ELSE (GLIB2_FOUND) + IF (GLIB2_FIND_REQUIRED) + MESSAGE (SEND_ERROR "Could not find GLib2") + ENDIF (GLIB2_FIND_REQUIRED) + ENDIF (GLIB2_FOUND) + + # show the GLIB2_INCLUDE_DIRS and GLIB2_LIBRARIES variables only in the advanced view + MARK_AS_ADVANCED(GLIB2_INCLUDE_DIRS GLIB2_LIBRARIES) + MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARY) + MARK_AS_ADVANCED(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARY) + +ENDIF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS) + +IF ( WIN32 ) + # include libiconv for win32 + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h PATH_SUFFIXES glib-2.0) + + FIND_LIBRARY(LIBICONV_LIBRARY NAMES iconv) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) +ENDIF ( WIN32 ) + +IF ( GLIB2_FOUND ) + # Check if system has a newer version of glib + # which supports g_regex_match_simple + INCLUDE( CheckIncludeFiles ) + SET( CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS} ) + CHECK_INCLUDE_FILES ( glib/gregex.h HAVE_GLIB_GREGEX_H ) + CHECK_INCLUDE_FILES ( glib/gchecksum.h HAVE_GLIB_GCHECKSUM_H ) + # Reset CMAKE_REQUIRED_INCLUDES + SET( CMAKE_REQUIRED_INCLUDES "" ) +ENDIF( GLIB2_FOUND ) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindWireshark.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindWireshark.cmake new file mode 100644 index 0000000..16fabed --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/FindWireshark.cmake @@ -0,0 +1,28 @@ +# +# Try to find the wireshark library and its includes +# +# This snippet sets the following variables: +# WIRESHARK_FOUND True if wireshark library got found +# WIRESHARK_INCLUDE_DIRS Location of the wireshark headers +# WIRESHARK_LIBRARIES List of libraries to use wireshark +# +# Copyright (c) 2011 Reinhold Kainhofer +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# wireshark does not install its library with pkg-config information, +# so we need to manually find the libraries and headers + +FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/packet.h PATH_SUFFIXES wireshark ) +FIND_LIBRARY( WIRESHARK_LIBRARIES wireshark ) + +# Report results +IF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + SET( WIRESHARK_FOUND 1 ) +ELSE ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + MESSAGE( SEND_ERROR "Could NOT find the wireshark library and headers" ) +ENDIF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/UseMakeDissectorReg.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/UseMakeDissectorReg.cmake new file mode 100644 index 0000000..e7e1a73 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/cmake/UseMakeDissectorReg.cmake @@ -0,0 +1,33 @@ +# +# $Id: UseMakeDissectorReg.cmake 33616 2010-07-22 12:18:36Z stig $ +# +MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype ) + # FIXME: Only the Python stuff has been implemented + # Make this into a MACRO, to avoid duplication with plugins/.../ + #register.c: $(plugin_src) $(ALL_DISSECTORS_SRC) $(top_srcdir)/tools/make-dissector-reg \ + # $(top_srcdir)/tools/make-dissector-reg.py + # @if test -n "$(PYTHON)"; then \ + # echo Making register.c with python ; \ + # $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + # dissectors $(ALL_DISSECTORS_SRC) ; \ + # else \ + # echo Making register.c with shell script ; \ + # $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + # dissectors $(plugin_src) $(ALL_DISSECTORS_SRC) ; \ + # fi + set( _sources ${ARGN} ) + ADD_CUSTOM_COMMAND( + OUTPUT + ${_outputfile} + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ${CMAKE_CURRENT_SOURCE_DIR} + ${_registertype} + ${_sources} + DEPENDS + ${_sources} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ) +ENDMACRO(REGISTER_DISSECTOR_FILES) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.h b/libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.h new file mode 100644 index 0000000..7dfa9cd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.h @@ -0,0 +1,17 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "btle" + + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "0.0.1" + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.nmake b/libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.nmake new file mode 100644 index 0000000..d67b402 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/moduleinfo.nmake @@ -0,0 +1,28 @@ +# +# $Id: moduleinfo.nmake 20155 2006-12-19 22:22:34Z jake $ +# + +# The name +PACKAGE=btle + +# The version +MODULE_VERSION_MAJOR=0 +MODULE_VERSION_MINOR=0 +MODULE_VERSION_MICRO=0 +MODULE_VERSION_EXTRA=1 + +# +# The RC_VERSION should be comma-separated, not dot-separated, +# as per Graham Bloice's message in +# +# http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html +# +# "The RC_VERSION variable in config.nmake should be comma separated. +# This allows the resources to be built correctly and the version +# number to be correctly displayed in the explorer properties dialog +# for the executables, and XP's tooltip, rather than 0.0.0.0." +# + +MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA) +RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/packet-btatt.c b/libbtbb-2015-10-R1/wireshark/plugins/btatt/packet-btatt.c new file mode 100644 index 0000000..c913be1 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/packet-btatt.c @@ -0,0 +1,698 @@ +/* packet-btatt.c + * Routines for Bluetooth Attribute Protocol dissection + * + * Copyright 2012, Allan M. Madsen + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include + +#define BTL2CAP_PSM_ATT 0x001f +#define BTL2CAP_FIXED_CID_ATT 0x0004 + +/* Initialize the protocol and registered fields */ +static int proto_btatt = -1; + +static int hf_btatt_opcode = -1; +static int hf_btatt_handle = -1; +static int hf_btatt_starting_handle = -1; +static int hf_btatt_ending_handle = -1; +static int hf_btatt_group_end_handle = -1; +static int hf_btatt_value = -1; +static int hf_btatt_req_opcode_in_error = -1; +static int hf_btatt_handle_in_error = -1; +static int hf_btatt_error_code = -1; +static int hf_btatt_uuid16 = -1; +static int hf_btatt_uuid128 = -1; +static int hf_btatt_client_rx_mtu = -1; +static int hf_btatt_server_rx_mtu = -1; +static int hf_btatt_uuid_format = -1; +static int hf_btatt_length = -1; +static int hf_btatt_offset = -1; +static int hf_btatt_flags = -1; +static int hf_btatt_sign_counter = -1; +static int hf_btatt_signature = -1; + +/* Initialize the subtree pointers */ +static gint ett_btatt = -1; +static gint ett_btatt_list = -1; + +/* Opcodes */ +static const value_string opcode_vals[] = { + {0x01, "Error Response"}, + {0x02, "Exchange MTU Request"}, + {0x03, "Exchange MTU Response"}, + {0x04, "Find Information Request"}, + {0x05, "Find Information Response"}, + {0x06, "Find By Type Value Request"}, + {0x07, "Find By Type Value Response"}, + {0x08, "Read By Type Request"}, + {0x09, "Read By Type Response"}, + {0x0a, "Read Request"}, + {0x0b, "Read Response"}, + {0x0c, "Read Blob Request"}, + {0x0d, "Read Blob Response"}, + {0x0e, "Read Multiple Request"}, + {0x0f, "Read Multiple Response"}, + {0x10, "Read By Group Type Request"}, + {0x11, "Read By Group Type Response"}, + {0x12, "Write Request"}, + {0x13, "Write Response"}, + {0x16, "Prepare Write Request"}, + {0x17, "Prepare Write Response"}, + {0x18, "Execute Write Request"}, + {0x19, "Execute Write Response"}, + {0x1B, "Handle Value Notification"}, + {0x1D, "Handle Value Indication"}, + {0x1E, "Handle Value Confirmation"}, + {0x52, "Write Command"}, + {0xD2, "Signed Write Command"}, + {0x0, NULL} +}; + +/* Error codes */ +static const value_string error_vals[] = { + {0x01, "Invalid Handle"}, + {0x02, "Read Not Permitted"}, + {0x03, "Write Not Permitted"}, + {0x04, "Invalid PDU"}, + {0x05, "Insufficient Authentication"}, + {0x06, "Request Not Supported"}, + {0x07, "Invalid Offset"}, + {0x08, "Insufficient Authorization"}, + {0x09, "Prepare Queue Full"}, + {0x0a, "Attribute Not Found"}, + {0x0b, "Attribute Not Long"}, + {0x0c, "Insufficient Encryption Key Size"}, + {0x0d, "Invalid Attribute Value Length"}, + {0x0e, "Unlikely Error"}, + {0x0f, "Insufficient Encryption"}, + {0x10, "Unsupported Group Type"}, + {0x11, "Insufficient Resources"}, + {0x80, "Application Error"}, + {0xfd, "Improper Client Characteristic Configuration Descriptor"}, + {0xfe, "Procedure Already In Progress"}, + {0xff, "Out of Range"}, + {0x0, NULL} +}; + +static const value_string uuid_vals[] = { + /* Services - http://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */ + {0x1800, "Generic Access"}, + {0x1801, "Generic Attribute"}, + {0x1802, "Immediate Alert"}, + {0x1803, "Link Loss"}, + {0x1804, "Tx Power"}, + {0x1805, "Current Time Service"}, + {0x1806, "Reference Time Update Service"}, + {0x1807, "Next DST Change Service"}, + {0x1808, "Glucose"}, + {0x1809, "Health Thermometer"}, + {0x180a, "Device Information"}, + {0x180d, "Heart Rate"}, + {0x180e, "Phone Alert Status Service"}, + {0x180f, "Battery Service"}, + {0x1810, "Blood Pressure"}, + {0x1811, "Alert Notification Service"}, + {0x1812, "Human Interface Device"}, + {0x1813, "Scan Parameters"}, + {0x1814, "Running Speed and Cadence"}, + {0x1816, "Cycling Speed and Cadence"}, + /* Declarations - http://developer.bluetooth.org/gatt/declarations/Pages/DeclarationsHome.aspx */ + {0x2800, "GATT Primary Service Declaration"}, + {0x2801, "GATT Secondary Service Declaration"}, + {0x2802, "GATT Include Declaration"}, + {0x2803, "GATT Characteristic Declaration"}, + /* Descriptors - http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorsHomePage.aspx */ + {0x2900, "Characteristic Extended Properties"}, + {0x2901, "Characteristic User Description"}, + {0x2902, "Client Characteristic Configuration"}, + {0x2903, "Server Characteristic Configuration"}, + {0x2904, "Characteristic Presentation Format"}, + {0x2905, "Characteristic Aggregate Format"}, + {0x2906, "Valid Range"}, + {0x2907, "External Report Reference"}, + {0x2908, "Report Reference"}, + /* Characteristics - http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx */ + {0x2a00, "Device Name"}, + {0x2a01, "Appearance"}, + {0x2a02, "Peripheral Privacy Flag"}, + {0x2a03, "Reconnection Address"}, + {0x2a04, "Peripheral Preferred Connection Parameters"}, + {0x2a05, "Service Changed"}, + {0x2a06, "Alert Level"}, + {0x2a07, "Tx Power Level"}, + {0x2a08, "Date Time"}, + {0x2a09, "Day of Week"}, + {0x2a0a, "Day Date Time"}, + {0x2a0c, "Exact Time 256"}, + {0x2a0d, "DST Offset"}, + {0x2a0e, "Time Zone"}, + {0x2a0f, "Local Time Information"}, + {0x2a11, "Time with DST"}, + {0x2a12, "Time Accuracy"}, + {0x2a13, "Time Source"}, + {0x2a14, "Reference Time Information"}, + {0x2a16, "Time Update Control Point"}, + {0x2a17, "Time Update State"}, + {0x2a18, "Glucose Measurement"}, + {0x2a19, "Battery Level"}, + {0x2a1c, "Temperature Measurement"}, + {0x2a1d, "Temperature Type"}, + {0x2a1e, "Intermediate Temperature"}, + {0x2a21, "Measurement Interval"}, + {0x2a22, "Boot Keyboard Input Report"}, + {0x2a23, "System ID"}, + {0x2a24, "Model Number String"}, + {0x2a25, "Serial Number String"}, + {0x2a26, "Firmware Revision String"}, + {0x2a27, "Hardware Revision String"}, + {0x2a28, "Software Revision String"}, + {0x2a29, "Manufacturer Name String"}, + {0x2a2a, "IEEE 11073-20601 Reg. Cert. Data List"}, + {0x2a2b, "Current Time"}, + {0x2a31, "Scan Refresh"}, + {0x2a32, "Boot Keyboard Output Report"}, + {0x2a33, "Boot Mouse Input Report"}, + {0x2a34, "Glucose Measurement Context"}, + {0x2a35, "Blood Pressure Measurement"}, + {0x2a36, "Intermediate Cuff Pressure"}, + {0x2a37, "Heart Rate Measurement"}, + {0x2a38, "Body Sensor Location"}, + {0x2a39, "Heart Rate Control Point"}, + {0x2a3f, "Alert Status"}, + {0x2a40, "Ringer Control Point"}, + {0x2a41, "Ringer Setting"}, + {0x2a42, "Alert Category ID Bit Mask"}, + {0x2a43, "Alert Category ID"}, + {0x2a44, "Alert Notification Control Point"}, + {0x2a45, "Unread Alert Status"}, + {0x2a46, "New Alert"}, + {0x2a47, "Supported New Alert Category"}, + {0x2a48, "Supported Unread Alert Category"}, + {0x2a49, "Blood Pressure Feature"}, + {0x2a4a, "HID Information"}, + {0x2a4b, "Report Map"}, + {0x2a4c, "HID Control Point"}, + {0x2a4d, "Report"}, + {0x2a4e, "Protocol Mode"}, + {0x2a4f, "Scan Interval Window"}, + {0x2a50, "PnP ID"}, + {0x2a51, "Glucose Feature"}, + {0x2a52, "Record Access Control Point"}, + {0x2a53, "RSC Measurement"}, + {0x2a54, "RSC Feature"}, + {0x2a55, "SC Control Point"}, + {0x2a5b, "CSC Measurement"}, + {0x2a5c, "CSC Feature"}, + {0x2a5d, "Sensor Location"}, + {0x0, NULL} +}; +static value_string_ext uuid_vals_ext = VALUE_STRING_EXT_INIT(uuid_vals); + +static const value_string uuid_format_vals[] = { + {0x01, "16-bit UUIDs"}, + {0x02, "128-bit UUIDs"}, + {0x0, NULL} +}; + +static const value_string flags_vals[] = { + {0x00, "Cancel All"}, + {0x01, "Immediately Write All"}, + {0x0, NULL} +}; + +static void +dissect_btatt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + proto_item *ti, *item; + proto_tree *st, *ltree; + guint8 opcode; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATT"); + + switch (pinfo->p2p_dir) { + + case P2P_DIR_SENT: + col_add_str(pinfo->cinfo, COL_INFO, "Sent "); + break; + + case P2P_DIR_RECV: + col_add_str(pinfo->cinfo, COL_INFO, "Rcvd "); + break; + + case P2P_DIR_UNKNOWN: + break; + + default: + col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ", + pinfo->p2p_dir); + break; + } + + if (tvb_length_remaining(tvb, 0) < 1) + return; + + ti = proto_tree_add_item(tree, proto_btatt, tvb, 0, -1, ENC_NA); + st = proto_item_add_subtree(ti, ett_btatt); + + item = proto_tree_add_item(st, hf_btatt_opcode, tvb, 0, 1, ENC_LITTLE_ENDIAN); + opcode = tvb_get_guint8(tvb, 0); + offset++; + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(opcode, opcode_vals, "")); + + switch (opcode) { + case 0x01: /* Error Response */ + proto_tree_add_item(st, hf_btatt_req_opcode_in_error, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + proto_tree_add_item(st, hf_btatt_handle_in_error, tvb, offset, 2, ENC_LITTLE_ENDIAN); + col_append_fstr(pinfo->cinfo, COL_INFO, " - %s, Handle: 0x%04x", + val_to_str(tvb_get_guint8(tvb, offset+2), error_vals, ""), + tvb_get_letohs(tvb, offset)); + offset += 2; + proto_tree_add_item(st, hf_btatt_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + break; + + case 0x02: /* Exchange MTU Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Client Rx MTU: %u", tvb_get_letohs(tvb, offset)); + proto_tree_add_item(st, hf_btatt_client_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x03: /* Exchange MTU Response */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Server Rx MTU: %u", tvb_get_letohs(tvb, offset)); + proto_tree_add_item(st, hf_btatt_server_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x04: /* Find Information Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Handles: 0x%04x..0x%04x", + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x05: /* Find Information Response */ + { + guint8 format = tvb_get_guint8(tvb, offset); + + item = proto_tree_add_item(st, hf_btatt_uuid_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + if( format == 1 ) { + while( tvb_length_remaining(tvb, offset) > 0) { + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } + } + else if( format == 2 ) { + while( tvb_length_remaining(tvb, offset) > 0) { + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_uuid128, tvb, offset, 16, ENC_NA); + offset += 16; + } + } + else { + expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, "Unknown format"); + } + } + break; + + case 0x06: /* Find By Type Value Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x", + val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &uuid_vals_ext, ""), + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + + proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + if( tvb_length_remaining(tvb, offset) > 0) + proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA); + break; + + case 0x07: /* Find By Type Value Response */ + while( tvb_length_remaining(tvb, offset) > 0 ) { + item = proto_tree_add_text(st, tvb, offset, 4, + "Handles Info, Handle: 0x%04x, Group End Handle: 0x%04x", + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + + ltree = proto_item_add_subtree(item, ett_btatt_list); + + proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(ltree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } + break; + + case 0x08: /* Read By Type Request */ + case 0x10: /* Read By Group Type Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x", + val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &uuid_vals_ext, ""), + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + + proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + if (tvb_length_remaining(tvb, offset) == 2) { + proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } + else if (tvb_length_remaining(tvb, offset) == 16) { + item = proto_tree_add_item(st, hf_btatt_uuid128, tvb, offset, 16, ENC_NA); + proto_item_append_text(item, " (%s)", val_to_str_ext_const(tvb_get_letohs(tvb, offset), + &uuid_vals_ext, "")); + offset += 16; + } + break; + + case 0x09: /* Read By Type Response */ + { + guint8 length = tvb_get_guint8(tvb, offset); + + proto_tree_add_item(st, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + if(length > 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u", + tvb_length_remaining(tvb, offset)/length); + + while (tvb_length_remaining(tvb, offset) >= length) + { + item = proto_tree_add_text(st, tvb, offset, length, "Attribute Data, Handle: 0x%04x", + tvb_get_letohs(tvb, offset)); + + ltree = proto_item_add_subtree(item, ett_btatt_list); + + proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(ltree, hf_btatt_value, tvb, offset, length-2, ENC_LITTLE_ENDIAN); + offset += (length-2); + } + } + } + break; + + case 0x0a: /* Read Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset)); + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x0b: /* Read Response */ + case 0x0d: /* Read Blob Response */ + case 0x0f: /* Multiple Read Response */ + proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA); + break; + + case 0x0c: /* Read Blob Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u", + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x0e: /* Multiple Read Request */ + if(tvb_length_remaining(tvb, offset) < 4) { + expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, + "Too few handles, should be 2 or more"); + break; + } + + col_append_str(pinfo->cinfo, COL_INFO, ", Handles: "); + while (tvb_length_remaining(tvb, offset) >= 2) { + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + col_append_fstr(pinfo->cinfo, COL_INFO, "0x%04x ", tvb_get_letohs(tvb, offset)); + offset += 2; + } + break; + + case 0x11: /* Read By Group Type Response */ + { + guint8 length = tvb_get_guint8(tvb, offset); + + proto_tree_add_item(st, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + if(length > 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u", tvb_length_remaining(tvb, offset)/length); + + while (tvb_length_remaining(tvb, offset) >= length) { + item = proto_tree_add_text(st, tvb, offset, length, + "Attribute Data, Handle: 0x%04x, Group End Handle: 0x%04x", + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + + ltree = proto_item_add_subtree(item, ett_btatt_list); + + proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(ltree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(ltree, hf_btatt_value, tvb, offset, length-4, ENC_LITTLE_ENDIAN); + offset += (length-4); + } + } + } + break; + + case 0x12: /* Write Request */ + case 0x52: /* Write Command */ + case 0x1b: /* Handle Value Notification */ + case 0x1d: /* Handle Value Indication */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset)); + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA); + break; + + case 0x16: /* Prepare Write Request */ + case 0x17: /* Prepare Write Response */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u", + tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2)); + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA); + break; + + case 0x18: /* Execute Write Request */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str(tvb_get_guint8(tvb, offset), flags_vals, "")); + proto_tree_add_item(st, hf_btatt_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + break; + + case 0xd2: /* Signed Write Command */ + { + guint8 length; + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset)); + proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + length = tvb_length_remaining(tvb, offset); + if (length > 12) { + proto_tree_add_item(st, hf_btatt_value, tvb, offset, length-12, ENC_NA); + offset+=length-12; + } + + proto_tree_add_item(st, hf_btatt_sign_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset+=4; + proto_tree_add_item(st, hf_btatt_signature, tvb, offset, 8, ENC_NA); + offset+=8; + break; + } + default: + break; + } +} + +void +proto_register_btatt(void) +{ + module_t *module; + + static hf_register_info hf[] = { + {&hf_btatt_opcode, + {"Opcode", "btatt.opcode", + FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0, + NULL, HFILL} + }, + {&hf_btatt_handle, + {"Handle", "btatt.handle", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_starting_handle, + {"Starting Handle", "btatt.starting_handle", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_ending_handle, + {"Ending Handle", "btatt.ending_handle", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_group_end_handle, + {"Group End Handle", "btatt.group_end_handle", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_value, + {"Value", "btatt.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_req_opcode_in_error, + {"Request Opcode in Error", "btatt.req_opcode_in_error", + FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0, + NULL, HFILL} + }, + {&hf_btatt_handle_in_error, + {"Handle in Error", "btatt.handle_in_error", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_error_code, + {"Error Code", "btatt.error_code", + FT_UINT8, BASE_HEX, VALS(error_vals), 0x0, + NULL, HFILL} + }, + {&hf_btatt_uuid16, + {"UUID", "btatt.uuid16", + FT_UINT16, BASE_HEX |BASE_EXT_STRING, &uuid_vals_ext, 0x0, + NULL, HFILL} + }, + {&hf_btatt_uuid128, + {"UUID", "btatt.uuid128", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_client_rx_mtu, + {"Client Rx MTU", "btatt.client_rx_mtu", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_server_rx_mtu, + {"Server Rx MTU", "btatt.server_rx_mtu", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_uuid_format, + {"UUID Format", "btatt.uuid_format", + FT_UINT8, BASE_HEX, VALS(uuid_format_vals), 0x0, + NULL, HFILL} + }, + {&hf_btatt_length, + {"Length", "btatt.length", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of Handle/Value Pair", HFILL} + }, + {&hf_btatt_offset, + {"Offset", "btatt.offset", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_flags, + {"Flags", "btatt.flags", + FT_UINT8, BASE_HEX, VALS(flags_vals), 0x0, + NULL, HFILL} + }, + {&hf_btatt_sign_counter, + {"Sign Counter", "btatt.sign_counter", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL} + }, + {&hf_btatt_signature, + {"Signature", "btatt.signature", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL} + } + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_btatt, + &ett_btatt_list + }; + + /* Register the protocol name and description */ + proto_btatt = proto_register_protocol("Bluetooth Attribute Protocol", "ATT", "btatt"); + + register_dissector("btatt", dissect_btatt, proto_btatt); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_btatt, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + module = prefs_register_protocol(proto_btatt, NULL); + prefs_register_static_text_preference(module, "att.version", + "Bluetooth Protocol ATT version from Core 4.0", + "Version of protocol supported by this dissector."); +} + +void +proto_reg_handoff_btatt(void) +{ + dissector_handle_t btatt_handle; + + btatt_handle = find_dissector("btatt"); + dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_ATT, btatt_handle); + dissector_add_uint("btl2cap.cid", BTL2CAP_FIXED_CID_ATT, btatt_handle); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/plugin.rc.in b/libbtbb-2015-10-R1/wireshark/plugins/btatt/plugin.rc.in new file mode 100644 index 0000000..568dc07 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/plugin.rc.in @@ -0,0 +1,34 @@ +#include "winver.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @RC_MODULE_VERSION@ + PRODUCTVERSION @RC_VERSION@ + FILEFLAGSMASK 0x0L +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0" + VALUE "FileDescription", "@PACKAGE@ dissector\0" + VALUE "FileVersion", "@MODULE_VERSION@\0" + VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0" + VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs , Gilbert Ramirez and others\0" + VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0" + VALUE "ProductName", "Wireshark\0" + VALUE "ProductVersion", "@VERSION@\0" + VALUE "Comments", "Build with @MSVC_VARIANT@\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg b/libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg new file mode 100755 index 0000000..d2efa7c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg.py b/libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg.py new file mode 100755 index 0000000..060460c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btatt/tools/make-dissector-reg.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $ + +import os +import sys +import re +import pickle +from stat import * + +VERSION_KEY = '_VERSION' +CUR_VERSION = '$Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $' + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin" or registertype == "plugin_wtap": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by Makefile or Makefile.nmake. + */ +""" +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by the "register.c" target in + * epan/dissectors/Makefile or Makefile.nmake using information in + * epan/dissectors/register-cache.pkl. + * + * You can force this file to be regenerated completely by deleting + * it along with epan/dissectors/register-cache.pkl. + */ +""" +else: + print(("Unknown output type '%s'" % registertype)) + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append(os.path.join(srcdir, file)) + +if len(filenames) < 1: + print("No files found") + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +wtap_reg_regex0 = r"^(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" +wtap_reg_regex1 = r"void\s+(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ( 'wtap_register', re.compile(wtap_reg_regex0) ), + ( 'wtap_register', re.compile(wtap_reg_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION: + cache = {VERSION_KEY: CUR_VERSION} + except: + cache = {VERSION_KEY: CUR_VERSION} + + print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1))) + +# Grep +cache_hits = 0 +cache_misses = 0 +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and filename in cache: + cdict = cache[filename] + if cur_mtime == cdict['mtime']: + cache_hits += 1 +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + regs['wtap_register'].extend(cdict['wtap_register']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache_misses += 1 + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses))) + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print("No protocol registrations found") + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() +regs['wtap_register'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write(preamble) + +# Make the routine to register all protocols +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +elif registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +register_wtap_module(void) +{ +"""); + + for symbol in regs['wtap_register']: + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + reg_code.write(line) + + reg_code.write("}\n"); + reg_code.write("#endif\n"); +else: + reg_code.write(""" +static gulong proto_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['proto_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +static gulong handoff_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['handoff_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return proto_reg_count() + handoff_reg_count();" + reg_code.write(line) + + reg_code.write(""" +}\n +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/AUTHORS b/libbtbb-2015-10-R1/wireshark/plugins/btbb/AUTHORS new file mode 100644 index 0000000..71a4f07 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/AUTHORS @@ -0,0 +1,2 @@ +Authors: +Michael Ossmann diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/CMakeLists.txt b/libbtbb-2015-10-R1/wireshark/plugins/btbb/CMakeLists.txt new file mode 100644 index 0000000..4c29915 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/CMakeLists.txt @@ -0,0 +1,89 @@ +# CMakeLists.txt +# +# $Id: CMakeLists.txt 31995 2010-02-24 22:32:10Z jmayer $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +project(btbb-wireshark-plugin C) + +cmake_minimum_required(VERSION 2.6) +set(CMAKE_BACKWARDS_COMPATIBILITY 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +IF ( NOT CMAKE_INSTALL_LIBDIR ) + set(CMAKE_INSTALL_LIBDIR ~/.wireshark/plugins) +ENDIF ( NOT CMAKE_INSTALL_LIBDIR ) +MESSAGE (STATUS "Plugin will be installed in: ${CMAKE_INSTALL_LIBDIR}") + +INCLUDE(UseMakeDissectorReg) + +set(GLIB2_MIN_VERSION 2.4.0) + +find_package(GLIB2) +include_directories (${GLIB2_INCLUDE_DIRS}) + +find_package(Wireshark) +include_directories (${WIRESHARK_INCLUDE_DIRS}) + +set(LINK_MODE_LIB SHARED) +set(LINK_MODE_MODULE MODULE) + + +set(DISSECTOR_SRC + packet-btbb.c + packet-btbrlmp.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} +) + +set(CLEAN_FILES + ${PLUGIN_FILES} +) + +if (WERROR) + set_source_files_properties( + ${CLEAN_FILES} + PROPERTIES + COMPILE_FLAGS -Werror + ) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +register_dissector_files(plugin.c + plugin + ${DISSECTOR_SRC} +) + +add_library(btbb ${LINK_MODE_MODULE} + ${PLUGIN_FILES} +) +set_target_properties(btbb PROPERTIES PREFIX "") +set_target_properties(btbb PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}") + +target_link_libraries(btbb wireshark) + +install(TARGETS btbb + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/ NAMELINK_SKIP +) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btbb/COPYING new file mode 100644 index 0000000..aa0aea5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/README b/libbtbb-2015-10-R1/wireshark/plugins/btbb/README new file mode 100644 index 0000000..3ce11c6 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/README @@ -0,0 +1,17 @@ +BTBB Wireshark plugin + +This is the Bluetooth baseband plugin for Wireshark, it also includes an LMP +level dissector. + +To build this on Debian/Ubuntu/BackTrack linux distributions: + sudo apt-get install wireshark-dev wireshark + cd libbtbb/wireshark/plugins/btbb/ + mkdir build + cd build + cmake .. + make + make install + +This will install to the .wireshark/ in your home directory. To override this +set the DESTDIR environment variable when running cmake. + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/btbb-sample-mouse.pcap b/libbtbb-2015-10-R1/wireshark/plugins/btbb/btbb-sample-mouse.pcap new file mode 100644 index 0000000000000000000000000000000000000000..092c9ceca7c8f703912052a9719bac2d8a73e013 GIT binary patch literal 2541 zcmaKuTS!zv7{}*$+`F!tXr?CXQf@u;V3!q&E>Ms~L=f~)1X;bPS$Q{aX&Dk);=X7R zYT<+R6cW@!VPaMfVmBWu%@8#qh)zThft!7;m12svm3cw*97V?pGATCwA=-9RnJz)DGN&jB02{8sEqB~pvAVmAl8Ky9an(fO3oqM`2$ z^}2{H$XNe-SER_(?si=yX%ba;_(bH;B@)>%kJgp0uS*Wq5;po5?NWkaiLuTFHz?aJ z8fGb5>UX&7XpFlBIS9Wda)`01PoButjwDU1Na5t z_z|WXOAa*<_VO)~)|YOPcDcn&F^~BiKnWbKL0#IPfzF5w=nfi5&EAdjA$(`bA;#X7 zAT{08~TX~KYWeIA;!M;M7iCb^);(X6Gi8KpqFT)HkV`zGWMqpIXCBOCTzb$ z2KAn2s4+HOhmtVUSl|`HGHau}0|||@s>0DRJE~CA(pAFZdZScmeNC*YaP-~~dSQLK T6GwFmVdL{r{ +# Copyright (c) 2006 Philippe Bernery +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Alban Browaeys +# Copyright (c) 2008 Michael Bell +# Copyright (c) 2008-2009 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +IF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + # in cache already + SET(GLIB2_FOUND TRUE) +ELSE (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + + INCLUDE(FindPkgConfig) + + ## Glib + IF ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) + ELSE ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) + ENDIF ( GLIB2_FIND_REQUIRED ) + + IF ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0>=${GLIB2_MIN_VERSION} ) + ELSE ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0 ) + ENDIF ( GLIB2_MIN_VERSION ) + IF ( PKG_CONFIG_FOUND ) + IF ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( GLIB2_FOUND ) + ENDIF ( PKG_CONFIG_FOUND ) + + # Look for glib2 include dir and libraries w/o pkgconfig + IF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( + _glibconfig_include_DIR + NAMES + glibconfig.h + PATHS + /opt/gnome/lib64 + /opt/gnome/lib + /opt/lib/ + /opt/local/lib + /sw/lib/ + /usr/lib64 + /usr/lib + /usr/local/include + ${CMAKE_LIBRARY_PATH} + PATH_SUFFIXES + glib-2.0/include + ) + + FIND_PATH( + _glib2_include_DIR + NAMES + glib.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + PATH_SUFFIXES + glib-2.0 + ) + + #MESSAGE(STATUS "Glib headers: ${_glib2_include_DIR}") + + FIND_LIBRARY( + _glib2_link_DIR + NAMES + glib-2.0 + glib + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + IF ( _glib2_include_DIR AND _glib2_link_DIR ) + SET ( _glib2_FOUND TRUE ) + ENDIF ( _glib2_include_DIR AND _glib2_link_DIR ) + + + IF ( _glib2_FOUND ) + SET ( GLIB2_INCLUDE_DIRS ${_glib2_include_DIR} ${_glibconfig_include_DIR} ) + SET ( GLIB2_LIBRARIES ${_glib2_link_DIR} ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( _glib2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( _glib2_FOUND ) + + # Handle dependencies + # libintl + IF ( NOT LIBINTL_FOUND ) + FIND_PATH(LIBINTL_INCLUDE_DIR + NAMES + libintl.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + ) + + FIND_LIBRARY(LIBINTL_LIBRARY + NAMES + intl + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/local/lib + /usr/lib + ) + + IF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + SET (LIBINTL_FOUND TRUE) + ENDIF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + ENDIF ( NOT LIBINTL_FOUND ) + + # libiconv + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR + NAMES + iconv.h + PATHS + /opt/gnome/include + /opt/local/include + /opt/local/include + /sw/include + /sw/include + /usr/local/include + /usr/include + PATH_SUFFIXES + glib-2.0 + ) + + FIND_LIBRARY(LIBICONV_LIBRARY + NAMES + iconv + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + + IF (LIBINTL_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBINTL_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBINTL_INCLUDE_DIR}) + ENDIF (LIBINTL_FOUND) + + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) + + ENDIF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + ## + + IF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + SET (GLIB2_FOUND TRUE) + ENDIF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + + IF (GLIB2_FOUND) + IF (NOT GLIB2_FIND_QUIETLY) + MESSAGE (STATUS "Found GLib2: ${GLIB2_LIBRARIES} ${GLIB2_INCLUDE_DIRS}") + ENDIF (NOT GLIB2_FIND_QUIETLY) + ELSE (GLIB2_FOUND) + IF (GLIB2_FIND_REQUIRED) + MESSAGE (SEND_ERROR "Could not find GLib2") + ENDIF (GLIB2_FIND_REQUIRED) + ENDIF (GLIB2_FOUND) + + # show the GLIB2_INCLUDE_DIRS and GLIB2_LIBRARIES variables only in the advanced view + MARK_AS_ADVANCED(GLIB2_INCLUDE_DIRS GLIB2_LIBRARIES) + MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARY) + MARK_AS_ADVANCED(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARY) + +ENDIF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS) + +IF ( WIN32 ) + # include libiconv for win32 + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h PATH_SUFFIXES glib-2.0) + + FIND_LIBRARY(LIBICONV_LIBRARY NAMES iconv) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) +ENDIF ( WIN32 ) + +IF ( GLIB2_FOUND ) + # Check if system has a newer version of glib + # which supports g_regex_match_simple + INCLUDE( CheckIncludeFiles ) + SET( CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS} ) + CHECK_INCLUDE_FILES ( glib/gregex.h HAVE_GLIB_GREGEX_H ) + CHECK_INCLUDE_FILES ( glib/gchecksum.h HAVE_GLIB_GCHECKSUM_H ) + # Reset CMAKE_REQUIRED_INCLUDES + SET( CMAKE_REQUIRED_INCLUDES "" ) +ENDIF( GLIB2_FOUND ) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/FindWireshark.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/FindWireshark.cmake new file mode 100644 index 0000000..16fabed --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/FindWireshark.cmake @@ -0,0 +1,28 @@ +# +# Try to find the wireshark library and its includes +# +# This snippet sets the following variables: +# WIRESHARK_FOUND True if wireshark library got found +# WIRESHARK_INCLUDE_DIRS Location of the wireshark headers +# WIRESHARK_LIBRARIES List of libraries to use wireshark +# +# Copyright (c) 2011 Reinhold Kainhofer +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# wireshark does not install its library with pkg-config information, +# so we need to manually find the libraries and headers + +FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/packet.h PATH_SUFFIXES wireshark ) +FIND_LIBRARY( WIRESHARK_LIBRARIES wireshark ) + +# Report results +IF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + SET( WIRESHARK_FOUND 1 ) +ELSE ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + MESSAGE( SEND_ERROR "Could NOT find the wireshark library and headers" ) +ENDIF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/UseMakeDissectorReg.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/UseMakeDissectorReg.cmake new file mode 100644 index 0000000..e7e1a73 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/cmake/UseMakeDissectorReg.cmake @@ -0,0 +1,33 @@ +# +# $Id: UseMakeDissectorReg.cmake 33616 2010-07-22 12:18:36Z stig $ +# +MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype ) + # FIXME: Only the Python stuff has been implemented + # Make this into a MACRO, to avoid duplication with plugins/.../ + #register.c: $(plugin_src) $(ALL_DISSECTORS_SRC) $(top_srcdir)/tools/make-dissector-reg \ + # $(top_srcdir)/tools/make-dissector-reg.py + # @if test -n "$(PYTHON)"; then \ + # echo Making register.c with python ; \ + # $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + # dissectors $(ALL_DISSECTORS_SRC) ; \ + # else \ + # echo Making register.c with shell script ; \ + # $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + # dissectors $(plugin_src) $(ALL_DISSECTORS_SRC) ; \ + # fi + set( _sources ${ARGN} ) + ADD_CUSTOM_COMMAND( + OUTPUT + ${_outputfile} + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ${CMAKE_CURRENT_SOURCE_DIR} + ${_registertype} + ${_sources} + DEPENDS + ${_sources} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ) +ENDMACRO(REGISTER_DISSECTOR_FILES) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/moduleinfo.h b/libbtbb-2015-10-R1/wireshark/plugins/btbb/moduleinfo.h new file mode 100644 index 0000000..9a9a9c0 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/moduleinfo.h @@ -0,0 +1,17 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "btbb" + + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "0.0.1" + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbb.c b/libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbb.c new file mode 100644 index 0000000..a7d6b5c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbb.c @@ -0,0 +1,593 @@ +/* packet-btbb.c + * Routines for Bluetooth baseband dissection + * Copyright 2009, Michael Ossmann + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#include +#endif + +#include +#include + +/* function prototypes */ +void proto_reg_handoff_btbb(void); + +/* initialize the protocol and registered fields */ +static int proto_btbb = -1; +static int hf_btbb_meta = -1; +static int hf_btbb_dir = -1; +static int hf_btbb_clk = -1; +static int hf_btbb_channel = -1; +static int hf_btbb_addrbits = -1; +static int hf_btbb_clkbits = -1; +static int hf_btbb_pkthdr = -1; +static int hf_btbb_ltaddr = -1; +static int hf_btbb_type = -1; +static int hf_btbb_flags = -1; +static int hf_btbb_flow = -1; +static int hf_btbb_arqn = -1; +static int hf_btbb_seqn = -1; +static int hf_btbb_hec = -1; +static int hf_btbb_payload = -1; +static int hf_btbb_pldhdr = -1; +static int hf_btbb_llid = -1; +static int hf_btbb_pldflow = -1; +static int hf_btbb_length = -1; +static int hf_btbb_pldbody = -1; +static int hf_btbb_crc = -1; +static int hf_btbb_fhs_parity = -1; +static int hf_btbb_fhs_lap = -1; +static int hf_btbb_fhs_eir = -1; +static int hf_btbb_fhs_sr = -1; +static int hf_btbb_fhs_uap = -1; +static int hf_btbb_fhs_nap = -1; +static int hf_btbb_fhs_class = -1; +static int hf_btbb_fhs_ltaddr = -1; +static int hf_btbb_fhs_clk = -1; +static int hf_btbb_fhs_psmode = -1; + +/* field values */ +static const true_false_string direction = { + "Slave to Master", + "Master to Slave" +}; + +static const true_false_string clock_bits = { + "27", + "6" +}; + +static const true_false_string address_bits = { + "48 (NAP known)", + "32 (NAP unknown)" +}; + +static const value_string packet_types[] = { + /* generic names for unknown logical transport */ + { 0x0, "NULL" }, + { 0x1, "POLL" }, + { 0x2, "FHS" }, + { 0x3, "DM1" }, + { 0x4, "DH1/2-DH1" }, + { 0x5, "HV1" }, + { 0x6, "HV2/2-EV3" }, + { 0x7, "HV3/EV3/3-EV3" }, + { 0x8, "DV/3-DH1" }, + { 0x9, "AUX1" }, + { 0xa, "DM3/2-DH3" }, + { 0xb, "DH3/3-DH3" }, + { 0xc, "EV4/2-EV5" }, + { 0xd, "EV5/3-EV5" }, + { 0xe, "DM5/2-DH5" }, + { 0xf, "DH5/3-DH5" }, + { 0, NULL } +}; + +static const value_string sr_modes[] = { + { 0x0, "R0" }, + { 0x1, "R1" }, + { 0x2, "R2" }, + { 0x3, "Reserved" }, + { 0, NULL } +}; + +static const range_string ps_modes[] = { + { 0x0, 0x0, "Mandatory scan mode" }, + { 0x1, 0x7, "Reserved" }, + { 0, 0, NULL } +}; + +static const value_string llid_codes[] = { + { 0x0, "undefined" }, + { 0x1, "Continuation fragment of an L2CAP message (ACL-U)" }, + { 0x2, "Start of an L2CAP message or no fragmentation (ACL-U)" }, + { 0x3, "LMP message (ACL-C)" }, + { 0, NULL } +}; + +/* initialize the subtree pointers */ +static gint ett_btbb = -1; +static gint ett_btbb_meta = -1; +static gint ett_btbb_pkthdr = -1; +static gint ett_btbb_flags = -1; +static gint ett_btbb_payload = -1; +static gint ett_btbb_pldhdr = -1; + +/* subdissectors */ +static dissector_handle_t btbrlmp_handle = NULL; +static dissector_handle_t btl2cap_handle = NULL; + +/* packet header flags */ +static const int *flag_fields[] = { + &hf_btbb_flow, + &hf_btbb_arqn, + &hf_btbb_seqn, + NULL +}; + +/* one byte payload header */ +int +dissect_payload_header1(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_item *hdr_item; + proto_tree *hdr_tree; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + hdr_item = proto_tree_add_item(tree, hf_btbb_pldhdr, tvb, offset, 1, ENC_NA); + hdr_tree = proto_item_add_subtree(hdr_item, ett_btbb_pldhdr); + + proto_tree_add_item(hdr_tree, hf_btbb_llid, tvb, offset, 1, ENC_NA); + proto_tree_add_item(hdr_tree, hf_btbb_pldflow, tvb, offset, 1, ENC_NA); + proto_tree_add_item(hdr_tree, hf_btbb_length, tvb, offset, 1, ENC_NA); + + /* payload length */ + return tvb_get_guint8(tvb, offset) >> 3; +} + +void +dissect_fhs(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_item *fhs_item, *psmode_item; + proto_tree *fhs_tree; + const gchar *description; + guint8 psmode; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) == 20); + + fhs_item = proto_tree_add_item(tree, hf_btbb_payload, tvb, offset, -1, ENC_NA); + fhs_tree = proto_item_add_subtree(fhs_item, ett_btbb_payload); + + /* Use proto_tree_add_bits_item() to get around 32bit limit on bitmasks */ + proto_tree_add_bits_item(fhs_tree, hf_btbb_fhs_parity, tvb, offset*8, 34, ENC_LITTLE_ENDIAN); + /* proto_tree_add_item(fhs_tree, hf_btbb_fhs_parity, tvb, offset, 5, ENC_LITTLE_ENDIAN); */ + offset += 4; + + proto_tree_add_item(fhs_tree, hf_btbb_fhs_lap, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 3; + + proto_tree_add_item(fhs_tree, hf_btbb_fhs_eir, tvb, offset, 1, ENC_NA); + /* skipping 1 undefined bit */ + proto_tree_add_item(fhs_tree, hf_btbb_fhs_sr, tvb, offset, 1, ENC_NA); + /* skipping 2 reserved bits */ + offset += 1; + + proto_tree_add_item(fhs_tree, hf_btbb_fhs_uap, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(fhs_tree, hf_btbb_fhs_nap, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(fhs_tree, hf_btbb_fhs_class, tvb, offset, 3, ENC_LITTLE_ENDIAN); + offset += 3; + + proto_tree_add_item(fhs_tree, hf_btbb_fhs_ltaddr, tvb, offset, 1, ENC_NA); + proto_tree_add_item(fhs_tree, hf_btbb_fhs_clk, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 3; + + psmode = tvb_get_guint8(tvb, offset); + description = try_rval_to_str(psmode, ps_modes); + psmode_item = proto_tree_add_item(fhs_tree, hf_btbb_fhs_psmode, tvb, offset, 1, ENC_NA); + if (description) + proto_item_append_text(psmode_item, " (%s)", description); + offset += 1; + + proto_tree_add_item(fhs_tree, hf_btbb_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; +} + +void +dissect_dm1(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) +{ + int len; /* payload length indicated by payload header */ + int llid; /* logical link id */ + int l2len; /* length indicated by l2cap header */ + proto_item *dm1_item; + proto_tree *dm1_tree; + tvbuff_t *pld_tvb; + + /* + * FIXME + * I'm probably doing a terrible, terrible thing here, but it gets my + * initial test cases working. + */ + guint16 fake_acl_data; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + dm1_item = proto_tree_add_item(tree, hf_btbb_payload, tvb, offset, -1, ENC_NA); + dm1_tree = proto_item_add_subtree(dm1_item, ett_btbb_payload); + + len = dissect_payload_header1(dm1_tree, tvb, offset); + llid = tvb_get_guint8(tvb, offset) & 0x3; + offset += 1; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) == len + 2); + + if (llid == 3 && btbrlmp_handle) { + /* LMP */ + pld_tvb = tvb_new_subset(tvb, offset, len, len); + call_dissector(btbrlmp_handle, pld_tvb, pinfo, dm1_tree); + } else if (llid == 2 && btl2cap_handle) { + /* unfragmented L2CAP or start of fragment */ + l2len = tvb_get_letohs(tvb, offset); + if (l2len + 4 == len) { + /* unfragmented */ + pinfo->private_data = &fake_acl_data; + pld_tvb = tvb_new_subset(tvb, offset, len, len); + call_dissector(btl2cap_handle, pld_tvb, pinfo, dm1_tree); + } else { + /* start of fragment */ + proto_tree_add_item(dm1_tree, hf_btbb_pldbody, tvb, offset, len, ENC_NA); + } + } else { + proto_tree_add_item(dm1_tree, hf_btbb_pldbody, tvb, offset, len, ENC_NA); + } + offset += len; + + proto_tree_add_item(dm1_tree, hf_btbb_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; +} + +/* dissect a packet */ +static int +dissect_btbb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *btbb_item, *meta_item, *pkthdr_item; + proto_tree *btbb_tree, *meta_tree, *pkthdr_tree; + int offset; + /* Avoid error: 'type' may be used uninitialized in this function */ + guint8 type = 0xff; + const gchar *info; + + /* sanity check: length */ + if (tvb_length(tvb) > 0 && tvb_length(tvb) < 9) + /* bad length: look for a different dissector */ + return 0; + + /* maybe should verify HEC */ + + /* make entries in protocol column and info column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bluetooth"); + + if (tvb_length(tvb) == 0) { + info = "ID"; + } else { + type = (tvb_get_guint8(tvb, 6) >> 3) & 0x0f; + info = val_to_str(type, packet_types, "Unknown type: 0x%x"); + } + + col_clear(pinfo->cinfo, COL_INFO); + col_add_str(pinfo->cinfo, COL_INFO, info); + + /* see if we are being asked for details */ + if (tree) { + + /* create display subtree for the protocol */ + offset = 0; + btbb_item = proto_tree_add_item(tree, proto_btbb, tvb, offset, -1, ENC_NA); + btbb_tree = proto_item_add_subtree(btbb_item, ett_btbb); + + /* ID packets have no header, no payload */ + if (tvb_length(tvb) == 0) + return 1; + + /* meta data */ + meta_item = proto_tree_add_item(btbb_tree, hf_btbb_meta, tvb, offset, 3, ENC_NA); + meta_tree = proto_item_add_subtree(meta_item, ett_btbb_meta); + + proto_tree_add_item(meta_tree, hf_btbb_dir, tvb, offset, 1, ENC_NA); + proto_tree_add_item(meta_tree, hf_btbb_clk, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(meta_tree, hf_btbb_channel, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(meta_tree, hf_btbb_clkbits, tvb, offset, 1, ENC_NA); + proto_tree_add_item(meta_tree, hf_btbb_addrbits, tvb, offset, 1, ENC_NA); + offset += 1; + + /* packet header */ + pkthdr_item = proto_tree_add_item(btbb_tree, hf_btbb_pkthdr, tvb, offset, 3, ENC_NA); + pkthdr_tree = proto_item_add_subtree(pkthdr_item, ett_btbb_pkthdr); + + proto_tree_add_item(pkthdr_tree, hf_btbb_ltaddr, tvb, offset, 1, ENC_NA); + proto_tree_add_item(pkthdr_tree, hf_btbb_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_bitmask(pkthdr_tree, tvb, offset, hf_btbb_flags, + ett_btbb_flags, flag_fields, ENC_NA); + offset += 1; + proto_tree_add_item(pkthdr_tree, hf_btbb_hec, tvb, offset, 1, ENC_NA); + offset += 1; + + /* payload */ + switch (type) { + case 0x0: /* NULL */ + case 0x1: /* POLL */ + break; + case 0x2: /* FHS */ + dissect_fhs(btbb_tree, tvb, offset); + break; + case 0x3: /* DM1 */ + dissect_dm1(btbb_tree, tvb, pinfo, offset); + break; + case 0x4: /* DH1/2-DH1 */ + dissect_dm1(btbb_tree, tvb, pinfo, offset); + break; + case 0x5: /* HV1 */ + case 0x6: /* HV2/2-EV3 */ + case 0x7: /* HV3/EV3/3-EV3 */ + case 0x8: /* DV/3-DH1 */ + case 0x9: /* AUX1 */ + case 0xa: /* DM3/2-DH3 */ + case 0xb: /* DH3/3-DH3 */ + case 0xc: /* EV4/2-EV5 */ + case 0xd: /* EV5/3-EV5 */ + case 0xe: /* DM5/2-DH5 */ + case 0xf: /* DH5/3-DH5 */ + proto_tree_add_item(btbb_tree, hf_btbb_payload, tvb, offset, -1, ENC_NA); + break; + default: + break; + } + } + + /* Return the amount of data this dissector was able to dissect */ + return tvb_length(tvb); +} + +/* register the protocol with Wireshark */ +void +proto_register_btbb(void) +{ + /* list of fields */ + static hf_register_info hf[] = { + { &hf_btbb_meta, + { "Meta Data", "btbb.meta", + FT_NONE, BASE_NONE, NULL, 0x0, + "Meta Data About the Packet", HFILL } + }, + { &hf_btbb_dir, + { "Direction", "btbb.dir", + FT_BOOLEAN, 8, TFS(&direction), 0x01, + "Direction of Transmission", HFILL } + }, + { &hf_btbb_clk, + { "CLK", "btbb.clk", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Clock bits 1 through 27", HFILL } + }, + { &hf_btbb_channel, + { "Channel", "btbb.channel", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Channel (0-78)", HFILL } + }, + { &hf_btbb_clkbits, + { "Known Clock Bits", "btbb.clkbits", + FT_BOOLEAN, 8, TFS(&clock_bits), 0x01, + "Number of Known Master CLK Bits (6 or 27)", HFILL } + }, + { &hf_btbb_addrbits, + { "Known Address Bits", "btbb.addrbits", + FT_BOOLEAN, 8, TFS(&address_bits), 0x02, + "Number of Known Bits of BD_ADDR (32 or 48)", HFILL } + }, + { &hf_btbb_pkthdr, + { "Packet Header", "btbb.pkthdr", + FT_NONE, BASE_NONE, NULL, 0x0, + "Bluetooth Baseband Packet Header", HFILL } + }, + { &hf_btbb_ltaddr, + { "LT_ADDR", "btbb.lt_addr", + FT_UINT8, BASE_HEX, NULL, 0x07, + "Logical Transport Address", HFILL } + }, + { &hf_btbb_type, + { "TYPE", "btbb.type", + FT_UINT8, BASE_HEX, VALS(packet_types), 0x78, + "Packet Type", HFILL } + }, + { &hf_btbb_flags, + { "Flags", "btbb.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Packet Header Flags", HFILL } + }, + { &hf_btbb_flow, + { "FLOW", "btbb.flow", + FT_BOOLEAN, 8, NULL, 0x01, + "Flow control indication", HFILL } + }, + { &hf_btbb_arqn, + { "ARQN", "btbb.arqn", + FT_BOOLEAN, 8, NULL, 0x02, + "Acknowledgment indication", HFILL } + }, + { &hf_btbb_seqn, + { "SEQN", "btbb.seqn", + FT_BOOLEAN, 8, NULL, 0x04, + "Sequence number", HFILL } + }, + { &hf_btbb_hec, + { "HEC", "btbb.lt_addr", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Header Error Check", HFILL } + }, + { &hf_btbb_payload, + { "Payload", "btbb.payload", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbb_llid, + { "LLID", "btbb.llid", + FT_UINT8, BASE_HEX, VALS(llid_codes), 0x03, + "Logical Link ID", HFILL } + }, + { &hf_btbb_pldflow, + { "Flow", "btbb.flow", + FT_BOOLEAN, 8, NULL, 0x04, + "Payload Flow indication", HFILL } + }, + { &hf_btbb_length, + { "Length", "btbb.length", + FT_UINT8, BASE_DEC, NULL, 0xf8, + "Payload Length", HFILL } + }, + { &hf_btbb_pldhdr, + { "Payload Header", "btbb.pldhdr", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbb_pldbody, + { "Payload Body", "btbb.pldbody", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbb_crc, + { "CRC", "btbb.crc", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Payload CRC", HFILL } + }, + { &hf_btbb_fhs_parity, + { "Parity", "btbb.parity", + /* FIXME this doesn't work because bitmasks can only be 32 bits */ + FT_UINT64, BASE_HEX, NULL, /*0x00000003ffffffffULL,*/ 0x0, + "LAP parity", HFILL } + }, + { &hf_btbb_fhs_lap, + { "LAP", "btbb.lap", + FT_UINT24, BASE_HEX, NULL, 0x03fffffc, + "Lower Address Part", HFILL } + }, + { &hf_btbb_fhs_eir, + { "EIR", "btbb.eir", + FT_BOOLEAN, 8, NULL, 0x04, + "Extended Inquiry Response packet may follow", HFILL } + }, + { &hf_btbb_fhs_sr, + { "SR", "btbb.sr", + FT_UINT8, BASE_HEX, VALS(sr_modes), 0x30, + "Scan Repetition", HFILL } + }, + { &hf_btbb_fhs_uap, + { "UAP", "btbb.uap", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Upper Address Part", HFILL } + }, + { &hf_btbb_fhs_nap, + { "NAP", "btbb.nap", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Non-Significant Address Part", HFILL } + }, + { &hf_btbb_fhs_class, /* FIXME break out further */ + { "Class of Device", "btbb.class", + FT_UINT24, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbb_fhs_ltaddr, + { "LT_ADDR", "btbb.lt_addr", + FT_UINT8, BASE_HEX, NULL, 0x07, + "Logical Transport Address", HFILL } + }, + { &hf_btbb_fhs_clk, + { "CLK", "btbb.clk", + FT_UINT32, BASE_HEX, NULL, 0x1ffffff8, + "Clock bits 2 through 27", HFILL } + }, + { &hf_btbb_fhs_psmode, + { "Page Scan Mode", "btbb.psmode", + FT_UINT8, BASE_HEX, NULL, 0xe0, + NULL, HFILL } + }, + }; + + /* protocol subtree arrays */ + static gint *ett[] = { + &ett_btbb, + &ett_btbb_meta, + &ett_btbb_pkthdr, + &ett_btbb_flags, + &ett_btbb_payload, + &ett_btbb_pldhdr, + }; + + /* register the protocol name and description */ + proto_btbb = proto_register_protocol( + "Bluetooth Baseband", /* full name */ + "BT Baseband", /* short name */ + "btbb" /* abbreviation (e.g. for filters) */ + ); + + /* register the header fields and subtrees used */ + proto_register_field_array(proto_btbb, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_reg_handoff_btbb(void) +{ + dissector_handle_t btbb_handle; + + btbb_handle = new_create_dissector_handle(dissect_btbb, proto_btbb); + /* hijacking this ethertype */ + dissector_add_uint("ethertype", 0xFFF0, btbb_handle); + /* dissector_add_uint("wtap_encap", WTAP_ENCAP_BLUETOOTH_BASEBAND, btbb_handle); */ + + btbrlmp_handle = find_dissector("btbrlmp"); + btl2cap_handle = find_dissector("btl2cap"); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbrlmp.c b/libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbrlmp.c new file mode 100644 index 0000000..aba1bfe --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/packet-btbrlmp.c @@ -0,0 +1,2887 @@ +/* packet-btbrlmp.c + * Routines for Bluetooth LMP dissection + * Copyright 2009, Michael Ossmann + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#include +#endif + +#include /* needed for epan/gcc-4.x */ +#include +#include + +/* LMP opcodes */ +#define LMP_NAME_REQ 1 +#define LMP_NAME_RES 2 +#define LMP_ACCEPTED 3 +#define LMP_NOT_ACCEPTED 4 +#define LMP_CLKOFFSET_REQ 5 +#define LMP_CLKOFFSET_RES 6 +#define LMP_DETACH 7 +#define LMP_IN_RAND 8 +#define LMP_COMB_KEY 9 +#define LMP_UNIT_KEY 10 +#define LMP_AU_RAND 11 +#define LMP_SRES 12 +#define LMP_TEMP_RAND 13 +#define LMP_TEMP_KEY 14 +#define LMP_ENCRYPTION_MODE_REQ 15 +#define LMP_ENCRYPTION_KEY_SIZE_REQ 16 +#define LMP_START_ENCRYPTION_REQ 17 +#define LMP_STOP_ENCRYPTION_REQ 18 +#define LMP_SWITCH_REQ 19 +#define LMP_HOLD 20 +#define LMP_HOLD_REQ 21 +#define LMP_SNIFF_REQ 23 +#define LMP_UNSNIFF_REQ 24 +#define LMP_PARK_REQ 25 +#define LMP_SET_BROADCAST_SCAN_WINDOW 27 +#define LMP_MODIFY_BEACON 28 +#define LMP_UNPARK_BD_ADDR_REQ 29 +#define LMP_UNPARK_PM_ADDR_REQ 30 +#define LMP_INCR_POWER_REQ 31 +#define LMP_DECR_POWER_REQ 32 +#define LMP_MAX_POWER 33 +#define LMP_MIN_POWER 34 +#define LMP_AUTO_RATE 35 +#define LMP_PREFERRED_RATE 36 +#define LMP_VERSION_REQ 37 +#define LMP_VERSION_RES 38 +#define LMP_FEATURES_REQ 39 +#define LMP_FEATURES_RES 40 +#define LMP_QUALITY_OF_SERVICE 41 +#define LMP_QUALITY_OF_SERVICE_REQ 42 +#define LMP_SCO_LINK_REQ 43 +#define LMP_REMOVE_SCO_LINK_REQ 44 +#define LMP_MAX_SLOT 45 +#define LMP_MAX_SLOT_REQ 46 +#define LMP_TIMING_ACCURACY_REQ 47 +#define LMP_TIMING_ACCURACY_RES 48 +#define LMP_SETUP_COMPLETE 49 +#define LMP_USE_SEMI_PERMANENT_KEY 50 +#define LMP_HOST_CONNECTION_REQ 51 +#define LMP_SLOT_OFFSET 52 +#define LMP_PAGE_MODE_REQ 53 +#define LMP_PAGE_SCAN_MODE_REQ 54 +#define LMP_SUPERVISION_TIMEOUT 55 +#define LMP_TEST_ACTIVATE 56 +#define LMP_TEST_CONTROL 57 +#define LMP_ENCRYPTION_KEY_SIZE_MASK_REQ 58 +#define LMP_ENCRYPTION_KEY_SIZE_MASK_RES 59 +#define LMP_SET_AFH 60 +#define LMP_ENCAPSULATED_HEADER 61 +#define LMP_ENCAPSULATED_PAYLOAD 62 +#define LMP_SIMPLE_PAIRING_CONFIRM 63 +#define LMP_SIMPLE_PAIRING_NUMBER 64 +#define LMP_DHKEY_CHECK 65 +#define LMP_ESCAPE_1 124 +#define LMP_ESCAPE_2 125 +#define LMP_ESCAPE_3 126 +#define LMP_ESCAPE_4 127 + +/* LMP extended opcodes */ +#define LMP_ACCEPTED_EXT 1 +#define LMP_NOT_ACCEPTED_EXT 2 +#define LMP_FEATURES_REQ_EXT 3 +#define LMP_FEATURES_RES_EXT 4 +#define LMP_PACKET_TYPE_TABLE_REQ 11 +#define LMP_ESCO_LINK_REQ 12 +#define LMP_REMOVE_ESCO_LINK_REQ 13 +#define LMP_CHANNEL_CLASSIFICATION_REQ 16 +#define LMP_CHANNEL_CLASSIFICATION 17 +#define LMP_SNIFF_SUBRATING_REQ 21 +#define LMP_SNIFF_SUBRATING_RES 22 +#define LMP_PAUSE_ENCRYPTION_REQ 23 +#define LMP_RESUME_ENCRYPTION_REQ 24 +#define LMP_IO_CAPABILITY_REQ 25 +#define LMP_IO_CAPABILITY_RES 26 +#define LMP_NUMERIC_COMPARISON_FAILED 27 +#define LMP_PASSKEY_FAILED 28 +#define LMP_OOB_FAILED 29 +#define LMP_KEYPRESS_NOTIFICATION 30 +#define LMP_POWER_CONTROL_REQ 31 +#define LMP_POWER_CONTROL_RES 32 + +/* initialize the protocol and registered fields */ +static int proto_btbrlmp = -1; +static int hf_lmp_accscheme = -1; +static int hf_lmp_afhchmap = -1; +static int hf_lmp_afhclass = -1; +static int hf_lmp_afhinst = -1; +static int hf_lmp_afhmaxintvl = -1; +static int hf_lmp_afhminintvl = -1; +static int hf_lmp_afhmode = -1; +static int hf_lmp_afhrptmode = -1; +static int hf_lmp_airmode = -1; +static int hf_lmp_araddr = -1; +static int hf_lmp_authreqs = -1; +static int hf_lmp_authres = -1; +static int hf_lmp_bdaddr = -1; +static int hf_lmp_bdaddr1 = -1; +static int hf_lmp_bdaddr2 = -1; +static int hf_lmp_bsw = -1; +static int hf_lmp_clkoffset = -1; +static int hf_lmp_commit = -1; +static int hf_lmp_confirm = -1; +static int hf_lmp_compid = -1; +static int hf_lmp_cryptmode = -1; +static int hf_lmp_daccess = -1; +static int hf_lmp_db = -1; +static int hf_lmp_dbsleep = -1; +static int hf_lmp_deltab = -1; +static int hf_lmp_desco = -1; +static int hf_lmp_drift = -1; +static int hf_lmp_dsco = -1; +static int hf_lmp_dsniff = -1; +static int hf_lmp_encdata = -1; +static int hf_lmp_enclen = -1; +static int hf_lmp_encmaj = -1; +static int hf_lmp_encmin = -1; +static int hf_lmp_eop = -1; +static int hf_lmp_eopinre = -1; +static int hf_lmp_escolenms = -1; +static int hf_lmp_escolensm = -1; +static int hf_lmp_escotypems = -1; +static int hf_lmp_escotypesm = -1; +static int hf_lmp_err = -1; +static int hf_lmp_escohdl = -1; +static int hf_lmp_escoltaddr = -1; +static int hf_lmp_features = -1; +static int hf_lmp_fpage = -1; +static int hf_lmp_htime = -1; +static int hf_lmp_hinst = -1; +static int hf_lmp_hopmode = -1; +static int hf_lmp_iocaps = -1; +static int hf_lmp_jitter = -1; +static int hf_lmp_key = -1; +static int hf_lmp_keysz = -1; +static int hf_lmp_ksmask = -1; +static int hf_lmp_ltaddr1 = -1; +static int hf_lmp_ltaddr2 = -1; +static int hf_lmp_ltaddr3 = -1; +static int hf_lmp_ltaddr4 = -1; +static int hf_lmp_ltaddr5 = -1; +static int hf_lmp_ltaddr6 = -1; +static int hf_lmp_ltaddr7 = -1; +static int hf_lmp_maccess = -1; +static int hf_lmp_maxslots = -1; +static int hf_lmp_maxsp = -1; +static int hf_lmp_maxss = -1; +static int hf_lmp_minsmt = -1; +static int hf_lmp_naccslots = -1; +static int hf_lmp_namefrag = -1; +static int hf_lmp_namelen = -1; +static int hf_lmp_nameoffset = -1; +static int hf_lmp_nb = -1; +static int hf_lmp_nbc = -1; +static int hf_lmp_nbsleep = -1; +static int hf_lmp_negstate = -1; +static int hf_lmp_nonce = -1; +static int hf_lmp_nottype = -1; +static int hf_lmp_npoll = -1; +static int hf_lmp_oobauthdata = -1; +static int hf_lmp_op = -1; +static int hf_lmp_opinre = -1; +static int hf_lmp_pagesch = -1; +static int hf_lmp_pcmode = -1; +static int hf_lmp_pkttype = -1; +static int hf_lmp_pkttypetbl = -1; +static int hf_lmp_pmaddr = -1; +static int hf_lmp_pmaddr1 = -1; +static int hf_lmp_pmaddr2 = -1; +static int hf_lmp_pmaddr3 = -1; +static int hf_lmp_pmaddr4 = -1; +static int hf_lmp_pmaddr5 = -1; +static int hf_lmp_pmaddr6 = -1; +static int hf_lmp_pmaddr7 = -1; +static int hf_lmp_pollintvl = -1; +static int hf_lmp_pollper = -1; +static int hf_lmp_pssettings = -1; +static int hf_lmp_pwradjreq = -1; +static int hf_lmp_pwradjres = -1; +static int hf_lmp_pwradj_8dpsk = -1; +static int hf_lmp_pwradj_dqpsk = -1; +static int hf_lmp_pwradj_gfsk = -1; +static int hf_lmp_rand = -1; +static int hf_lmp_rate = -1; +static int hf_lmp_rate_fec = -1; +static int hf_lmp_rate_size = -1; +static int hf_lmp_rate_type = -1; +static int hf_lmp_rate_edrsize = -1; +static int hf_lmp_rxfreq = -1; +static int hf_lmp_scohdl = -1; +static int hf_lmp_scopkt = -1; +static int hf_lmp_slotoffset = -1; +static int hf_lmp_sniffatt = -1; +static int hf_lmp_sniffsi = -1; +static int hf_lmp_sniffto = -1; +static int hf_lmp_subversnr = -1; +static int hf_lmp_suptimeout = -1; +static int hf_lmp_swinst = -1; +static int hf_lmp_taccess = -1; +static int hf_lmp_tb = -1; +static int hf_lmp_tesco = -1; +static int hf_lmp_testlen = -1; +static int hf_lmp_testscen = -1; +static int hf_lmp_tid = -1; +static int hf_lmp_timectrl = -1; +static int hf_lmp_time_change = -1; +static int hf_lmp_time_init = -1; +static int hf_lmp_time_accwin = -1; +static int hf_lmp_tsco = -1; +static int hf_lmp_tsniff = -1; +static int hf_lmp_txfreq = -1; +static int hf_lmp_versnr = -1; +static int hf_lmp_wesco = -1; + +/* timing control flags */ +static const int *timectrl_fields[] = { + &hf_lmp_time_change, + &hf_lmp_time_init, + &hf_lmp_time_accwin, + /* bits 3-7 reserved */ + NULL +}; + +static const true_false_string time_change = { + "timing change", + "no timing change" +}; + +static const true_false_string time_init = { + "use initialization 2", + "use initialization 1" +}; + +static const true_false_string time_accwin = { + "no access window", + "access window" +}; + +static const true_false_string fec = { + "do not use FEC", + "use FEC" +}; + +static const true_false_string tid = { + "transaction initiated by slave", + "transaction initiated by master" +}; + +/* short LMP opcodes */ +static const value_string opcode[] = { + { LMP_NAME_REQ, "LMP_name_req" }, + { LMP_NAME_RES, "LMP_name_res" }, + { LMP_ACCEPTED, "LMP_accepted" }, + { LMP_NOT_ACCEPTED, "LMP_not_accepted" }, + { LMP_CLKOFFSET_REQ, "LMP_clkoffset_req" }, + { LMP_CLKOFFSET_RES, "LMP_clkoffset_res" }, + { LMP_DETACH, "LMP_detach" }, + { LMP_IN_RAND, "LMP_in_rand" }, + { LMP_COMB_KEY, "LMP_comb_key" }, + { LMP_UNIT_KEY, "LMP_unit_key" }, + { LMP_AU_RAND, "LMP_au_rand" }, + { LMP_SRES, "LMP_sres" }, + { LMP_TEMP_RAND, "LMP_temp_rand" }, + { LMP_TEMP_KEY, "LMP_temp_key" }, + { LMP_ENCRYPTION_MODE_REQ, "LMP_encryption_mode_req" }, + { LMP_ENCRYPTION_KEY_SIZE_REQ, "LMP_encryption_key_size_req" }, + { LMP_START_ENCRYPTION_REQ, "LMP_start_encryption_req" }, + { LMP_STOP_ENCRYPTION_REQ, "LMP_stop_encryption_req" }, + { LMP_SWITCH_REQ, "LMP_switch_req" }, + { LMP_HOLD, "LMP_hold" }, + { LMP_HOLD_REQ, "LMP_hold_req" }, + { LMP_SNIFF_REQ, "LMP_sniff_req" }, + { LMP_UNSNIFF_REQ, "LMP_unsniff_req" }, + { LMP_PARK_REQ, "LMP_park_req" }, + { LMP_SET_BROADCAST_SCAN_WINDOW, "LMP_set_broadcast_scan_window" }, + { LMP_MODIFY_BEACON, "LMP_modify_beacon" }, + { LMP_UNPARK_BD_ADDR_REQ, "LMP_unpark_BD_ADDR_req" }, + { LMP_UNPARK_PM_ADDR_REQ, "LMP_unpark_PM_ADDR_req" }, + { LMP_INCR_POWER_REQ, "LMP_incr_power_req" }, + { LMP_DECR_POWER_REQ, "LMP_decr_power_req" }, + { LMP_MAX_POWER, "LMP_max_power" }, + { LMP_MIN_POWER, "LMP_min_power" }, + { LMP_AUTO_RATE, "LMP_auto_rate" }, + { LMP_PREFERRED_RATE, "LMP_preferred_rate" }, + { LMP_VERSION_REQ, "LMP_version_req" }, + { LMP_VERSION_RES, "LMP_version_res" }, + { LMP_FEATURES_REQ, "LMP_features_req" }, + { LMP_FEATURES_RES, "LMP_features_res" }, + { LMP_QUALITY_OF_SERVICE, "LMP_quality_of_service" }, + { LMP_QUALITY_OF_SERVICE_REQ, "LMP_quality_of_service_req" }, + { LMP_SCO_LINK_REQ, "LMP_SCO_link_req" }, + { LMP_REMOVE_SCO_LINK_REQ, "LMP_remove_SCO_link_req" }, + { LMP_MAX_SLOT, "LMP_max_slot" }, + { LMP_MAX_SLOT_REQ, "LMP_max_slot_req" }, + { LMP_TIMING_ACCURACY_REQ, "LMP_timing_accuracy_req" }, + { LMP_TIMING_ACCURACY_RES, "LMP_timing_accuracy_res" }, + { LMP_SETUP_COMPLETE, "LMP_setup_complete" }, + { LMP_USE_SEMI_PERMANENT_KEY, "LMP_use_semi_permanent_key" }, + { LMP_HOST_CONNECTION_REQ, "LMP_host_connection_req" }, + { LMP_SLOT_OFFSET, "LMP_slot_offset" }, + { LMP_PAGE_MODE_REQ, "LMP_page_mode_req" }, + { LMP_PAGE_SCAN_MODE_REQ, "LMP_page_scan_mode_req" }, + { LMP_SUPERVISION_TIMEOUT, "LMP_supervision_timeout" }, + { LMP_TEST_ACTIVATE, "LMP_test_activate" }, + { LMP_TEST_CONTROL, "LMP_test_control" }, + { LMP_ENCRYPTION_KEY_SIZE_MASK_REQ, "LMP_encryption_key_size_mask_req" }, + { LMP_ENCRYPTION_KEY_SIZE_MASK_RES, "LMP_encryption_key_size_mask_res" }, + { LMP_SET_AFH, "LMP_set_AFH" }, + { LMP_ENCAPSULATED_HEADER, "LMP_encapsulated_header" }, + { LMP_ENCAPSULATED_PAYLOAD, "LMP_encapsulated_payload" }, + { LMP_SIMPLE_PAIRING_CONFIRM, "LMP_Simple_Pairing_Confirm" }, + { LMP_SIMPLE_PAIRING_NUMBER, "LMP_Simple_Pairing_Number" }, + { LMP_DHKEY_CHECK, "LMP_DHkey_Check" }, + { LMP_ESCAPE_1, "Escape 1" }, + { LMP_ESCAPE_2, "Escape 2" }, + { LMP_ESCAPE_3, "Escape 3" }, + { LMP_ESCAPE_4, "Escape 4" }, + { 0, NULL } +}; + +/* extended LMP opcodes */ +static const value_string ext_opcode[] = { + { LMP_ACCEPTED_EXT, "LMP_accepted_ext" }, + { LMP_NOT_ACCEPTED_EXT, "LMP_not_accepted_ext" }, + { LMP_FEATURES_REQ_EXT, "LMP_features_req_ext" }, + { LMP_FEATURES_RES_EXT, "LMP_features_res_ext" }, + { LMP_PACKET_TYPE_TABLE_REQ, "LMP_packet_type_table_req" }, + { LMP_ESCO_LINK_REQ, "LMP_eSCO_link_req" }, + { LMP_REMOVE_ESCO_LINK_REQ, "LMP_remove_eSCO_link_req" }, + { LMP_CHANNEL_CLASSIFICATION_REQ, "LMP_channel_classification_req" }, + { LMP_CHANNEL_CLASSIFICATION, "LMP_channel_classification" }, + { LMP_SNIFF_SUBRATING_REQ, "LMP_sniff_subrating_req" }, + { LMP_SNIFF_SUBRATING_RES, "LMP_sniff_subrating_res" }, + { LMP_PAUSE_ENCRYPTION_REQ, "LMP_pause_encryption_req" }, + { LMP_RESUME_ENCRYPTION_REQ, "LMP_resume_encryption_req" }, + { LMP_IO_CAPABILITY_REQ, "LMP_IO_Capability_req" }, + { LMP_IO_CAPABILITY_RES, "LMP_IO_Capability_res" }, + { LMP_NUMERIC_COMPARISON_FAILED, "LMP_numeric_comparison_failed" }, + { LMP_PASSKEY_FAILED, "LMP_passkey_failed" }, + { LMP_OOB_FAILED, "LMP_oob_failed" }, + { LMP_KEYPRESS_NOTIFICATION, "LMP_keypress_notification" }, + { LMP_POWER_CONTROL_REQ, "LMP_power_control_req" }, + { LMP_POWER_CONTROL_RES, "LMP_power_control_res" }, + { 0, NULL } +}; + +/* LMP error codes */ +static const value_string error_code[] = { + { 0x00, "Success" }, + { 0x01, "Unknown HCI Command" }, + { 0x02, "Unknown Connection Identifier" }, + { 0x03, "Hardware Failure" }, + { 0x04, "Page Timeout" }, + { 0x05, "Authentication Failure" }, + { 0x06, "PIN or Key Missing" }, + { 0x07, "Memory Capacity Exceeded" }, + { 0x08, "Connection Timeout" }, + { 0x09, "Connection Limit Exceeded" }, + { 0x0A, "Synchronous Connection Limit To A Device Exceeded" }, + { 0x0B, "ACL Connection Already Exists" }, + { 0x0C, "Command Disallowed" }, + { 0x0D, "Connection Rejected due to Limited Resources" }, + { 0x0E, "Connection Rejected Due To Security Reasons" }, + { 0x0F, "Connection Rejected due to Unacceptable BD_ADDR" }, + { 0x10, "Connection Accept Timeout Exceeded" }, + { 0x11, "Unsupported Feature or Parameter Value" }, + { 0x12, "Invalid HCI Command Parameters" }, + { 0x13, "Remote User Terminated Connection" }, + { 0x14, "Remote Device Terminated Connection due to Low Resources" }, + { 0x15, "Remote Device Terminated Connection due to Power Off" }, + { 0x16, "Connection Terminated By Local Host" }, + { 0x17, "Repeated Attempts" }, + { 0x18, "Pairing Not Allowed" }, + { 0x19, "Unknown LMP PDU" }, + { 0x1A, "Unsupported Remote Feature / Unsupported LMP Feature" }, + { 0x1B, "SCO Offset Rejected" }, + { 0x1C, "SCO Interval Rejected" }, + { 0x1D, "SCO Air Mode Rejected" }, + { 0x1E, "Invalid LMP Parameters" }, + { 0x1F, "Unspecified Error" }, + { 0x20, "Unsupported LMP Parameter Value" }, + { 0x21, "Role Change Not Allowed" }, + { 0x22, "LMP Response Timeout" }, + { 0x23, "LMP Error Transaction Collision" }, + { 0x24, "LMP PDU Not Allowed" }, + { 0x25, "Encryption Mode Not Acceptable" }, + { 0x26, "Link Key Can Not be Changed" }, + { 0x27, "Requested QoS Not Supported" }, + { 0x28, "Instant Passed" }, + { 0x29, "Pairing With Unit Key Not Supported" }, + { 0x2A, "Different Transaction Collision" }, + { 0x2B, "Reserved" }, + { 0x2C, "QoS Unacceptable Parameter" }, + { 0x2D, "QoS Rejected" }, + { 0x2E, "Channel Classification Not Supported" }, + { 0x2F, "Insufficient Security" }, + { 0x30, "Parameter Out Of Mandatory Range" }, + { 0x31, "Reserved" }, + { 0x32, "Role Switch Pending" }, + { 0x33, "Reserved" }, + { 0x34, "Reserved Slot Violation" }, + { 0x35, "Role Switch Failed" }, + { 0x36, "Extended Inquiry Response Too Large" }, + { 0x37, "Secure Simple Pairing Not Supported By Host." }, + { 0x38, "Host Busy - Pairing" }, + { 0x39, "Connection Rejected due to No Suitable Channel Found" }, + { 0, NULL } +}; + +static const value_string encryption_mode[] = { + { 0, "no encryption" }, + { 1, "encryption" }, + { 2, "encryption" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string access_scheme[] = { + { 0, "polling technique" }, + /* 1 - 15 reserved */ + { 0, NULL } +}; + +static const value_string packet_size[] = { + { 0, "no packet-size preference available" }, + { 1, "use 1-slot packets" }, + { 2, "use 3-slot packets" }, + { 3, "use 5-slot packets" }, + { 0, NULL } +}; + +static const value_string edr_type[] = { + { 0, "use DM1 packets" }, + { 1, "use 2 Mbps packets" }, + { 2, "use 3 Mbps packets" }, + /* 3 reserved */ + { 0, NULL } +}; + +static const value_string versnr[] = { + { 0, "Bluetooth Core Specification 1.0b" }, + { 1, "Bluetooth Core Specification 1.1" }, + { 2, "Bluetooth Core Specification 1.2" }, + { 3, "Bluetooth Core Specification 2.0 + EDR" }, + { 4, "Bluetooth Core Specification 2.1 + EDR" }, + { 5, "Bluetooth Core Specification 3.0 + HS" }, + /* 6 - 255 reserved */ + { 0, NULL } +}; + +static const value_string compid[] = { + { 0, "Ericsson Technology Licensing" }, + { 1, "Nokia Mobile Phones" }, + { 2, "Intel Corp." }, + { 3, "IBM Corp." }, + { 4, "Toshiba Corp." }, + { 5, "3Com" }, + { 6, "Microsoft" }, + { 7, "Lucent" }, + { 8, "Motorola" }, + { 9, "Infineon Technologies AG" }, + { 10, "Cambridge Silicon Radio" }, + { 11, "Silicon Wave" }, + { 12, "Digianswer A/S" }, + { 13, "Texas Instruments Inc." }, + { 14, "Parthus Technologies Inc." }, + { 15, "Broadcom Corporation" }, + { 16, "Mitel Semiconductor" }, + { 17, "Widcomm, Inc." }, + { 18, "Zeevo, Inc." }, + { 19, "Atmel Corporation" }, + { 20, "Mitsubishi Electric Corporation" }, + { 21, "RTX Telecom A/S" }, + { 22, "KC Technology Inc." }, + { 23, "Newlogic" }, + { 24, "Transilica, Inc." }, + { 25, "Rohde & Schwarz GmbH & Co. KG" }, + { 26, "TTPCom Limited" }, + { 27, "Signia Technologies, Inc." }, + { 28, "Conexant Systems Inc." }, + { 29, "Qualcomm" }, + { 30, "Inventel" }, + { 31, "AVM Berlin" }, + { 32, "BandSpeed, Inc." }, + { 33, "Mansella Ltd" }, + { 34, "NEC Corporation" }, + { 35, "WavePlus Technology Co., Ltd." }, + { 36, "Alcatel" }, + { 37, "Philips Semiconductors" }, + { 38, "C Technologies" }, + { 39, "Open Interface" }, + { 40, "R F Micro Devices" }, + { 41, "Hitachi Ltd" }, + { 42, "Symbol Technologies, Inc." }, + { 43, "Tenovis" }, + { 44, "Macronix International Co. Ltd." }, + { 45, "GCT Semiconductor" }, + { 46, "Norwood Systems" }, + { 47, "MewTel Technology Inc." }, + { 48, "ST Microelectronics" }, + { 49, "Synopsys" }, + { 50, "Red-M (Communications) Ltd" }, + { 51, "Commil Ltd" }, + { 52, "Computer Access Technology Corporation (CATC)" }, + { 53, "Eclipse (HQ Espana) S.L." }, + { 54, "Renesas Technology Corp." }, + { 55, "Mobilian Corporation" }, + { 56, "Terax" }, + { 57, "Integrated System Solution Corp." }, + { 58, "Matsushita Electric Industrial Co., Ltd." }, + { 59, "Gennum Corporation" }, + { 60, "Research In Motion" }, + { 61, "IPextreme, Inc." }, + { 62, "Systems and Chips, Inc" }, + { 63, "Bluetooth SIG, Inc" }, + { 64, "Seiko Epson Corporation" }, + { 65, "Integrated Silicon Solution Taiwan, Inc." }, + { 66, "CONWISE Technology Corporation Ltd" }, + { 67, "PARROT SA" }, + { 68, "Socket Mobile" }, + { 69, "Atheros Communications, Inc." }, + { 70, "MediaTek, Inc." }, + { 71, "Bluegiga (tentative)" }, + { 72, "Marvell Technology Group Ltd." }, + { 73, "3DSP Corporation" }, + { 74, "Accel Semiconductor Ltd." }, + { 75, "Continental Automotive Systems" }, + { 76, "Apple, Inc." }, + { 77, "Staccato Communications, Inc." }, + { 78, "Avago Technologies" }, + { 79, "APT Ltd." }, + { 80, "SiRF Technology, Inc." }, + { 81, "Tzero Technologies, Inc." }, + { 82, "J&M Corporation" }, + { 83, "Free2move AB" }, + /* 84 - 65534 reserved */ + { 65535, "test" }, + { 0, NULL } +}; + +static const value_string sco_packet[] = { + { 0, "HV1" }, + { 1, "HV2" }, + { 2, "HV3" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string air_mode[] = { + { 0, "mu-law log" }, + { 1, "A-law log" }, + { 2, "CVSD" }, + { 3, "transparent data" }, + /* 4 - 255 reserved */ + { 0, NULL } +}; + +static const value_string paging_scheme[] = { + { 0, "mandatory scheme" }, + /* 1 - 255 reserved */ + { 0, NULL } +}; + +static const value_string paging_scheme_settings[] = { + /* for mandatory scheme: */ + { 0, "R0" }, + { 1, "R1" }, + { 2, "R2" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string afh_mode[] = { + { 0, "AFH disabled" }, + { 1, "AFH enabled" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string features_page[] = { + { 0, "standard features" }, + /* 1 - 255 other feature pages */ + { 0, NULL } +}; + +static const value_string packet_type_table[] = { + { 0, "1 Mbps only" }, + { 1, "2/3 Mbps" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string negotiation_state[] = { + { 0, "Initiate negotiation" }, + { 1, "The latest received set of negotiable parameters were possible but these parameters are preferred." }, + { 2, "The latest received set of negotiable parameters would cause a reserved slot violation." }, + { 3, "The latest received set of negotiable parameters would cause a latency violation." }, + { 4, "The latest received set of negotiable parameters are not supported." }, + /* 5 - 255 reserved */ + { 0, NULL } +}; + +static const value_string afh_reporting_mode[] = { + { 0, "AFH reporting disabled" }, + { 1, "AFH reporting enabled" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string io_capabilities[] = { + { 0, "Display Only" }, + { 1, "Display Yes/No" }, + { 2, "Keyboard Only" }, + { 3, "No Input/No Output" }, + /* 4 - 255 reserved */ + { 0, NULL } +}; + +static const value_string oob_auth_data[] = { + { 0, "No OOB Authentication Data received" }, + { 1, "OOB Authentication Data received" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string auth_requirements[] = { + { 0x00, "MITM Protection Not Required - No Bonding" }, + { 0x01, "MITM Protection Required - No Bonding" }, + { 0x02, "MITM Protection Not Required - Dedicated Bonding" }, + { 0x03, "MITM Protection Required - Dedicated Bonding" }, + { 0x04, "MITM Protection Not Required - General Bonding" }, + { 0x05, "MITM Protection Required - General Bonding" }, + /* 0x06 - 0xff reserved */ + { 0, NULL } +}; + +static const value_string power_adjust_req[] = { + { 0, "decrement power one step" }, + { 1, "increment power one step" }, + { 2, "increase to maximum power" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string power_adjust_res[] = { + { 0, "not supported" }, + { 1, "changed one step (not min or max)" }, + { 2, "max power" }, + { 3, "min power" }, + /* 4 - 255 reserved */ + { 0, NULL } +}; + +static const value_string test_scenario[] = { + { 0, "Pause Test Mode" }, + { 1, "Transmitter test - 0 pattern" }, + { 2, "Transmitter test - 1 pattern" }, + { 3, "Transmitter test - 1010 pattern" }, + { 4, "Pseudorandom bit sequence" }, + { 5, "Closed Loop Back - ACL packets" }, + { 6, "Closed Loop Back - Synchronous packets" }, + { 7, "ACL Packets without whitening" }, + { 8, "Synchronous Packets without whitening" }, + { 9, "Transmitter test - 1111 0000 pattern" }, + /* 10 - 254 reserved */ + { 255, "Exit Test Mode" }, + { 0, NULL } +}; + +static const value_string hopping_mode[] = { + { 0, "RX/TX on single frequency" }, + { 1, "Normal hopping" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string power_control_mode[] = { + { 0, "fixed TX output power" }, + { 1, "adaptive power control" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string esco_packet_type[] = { + { 0x00, "NULL/POLL" }, + { 0x07, "EV3" }, + { 0x0C, "EV4" }, + { 0x0D, "EV5" }, + { 0x26, "2-EV3" }, + { 0x2C, "2-EV5" }, + { 0x37, "3-EV3" }, + { 0x3D, "3-EV5" }, + /* other values reserved */ + { 0, NULL } +}; + +static const value_string notification_value[] = { + { 0, "passkey entry started" }, + { 1, "passkey digit entered" }, + { 2, "passkey digit erased" }, + { 3, "passkey cleared" }, + { 4, "passkey entry completed" }, + /* 5 - 255 reserved */ + { 0, NULL } +}; + +/* initialize the subtree pointers */ +static gint ett_lmp = -1; +static gint ett_lmp_pwradjres = -1; +static gint ett_lmp_rate = -1; +static gint ett_lmp_timectrl = -1; + +/* LMP PDUs with short opcodes */ + +void +dissect_name_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_nameoffset, tvb, offset, 1, ENC_NA); +} + +void +dissect_name_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_nameoffset, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_namelen, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_namefrag, tvb, offset, 14, ENC_ASCII|ENC_NA); +} + +void +dissect_accepted(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_NA); +} + +void +dissect_not_accepted(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_clkoffset_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_clkoffset_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_clkoffset, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_detach(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_in_rand(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_comb_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_unit_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_key, tvb, offset, 16, ENC_NA); +} + +void +dissect_au_rand(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_sres(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 4); + + proto_tree_add_item(tree, hf_lmp_authres, tvb, offset, 4, ENC_NA); +} + +void +dissect_temp_rand(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_temp_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_key, tvb, offset, 16, ENC_NA); +} + +void +dissect_encryption_mode_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_cryptmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_encryption_key_size_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_keysz, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_start_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_stop_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_switch_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 4); + + proto_tree_add_item(tree, hf_lmp_swinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); +} + +void +dissect_hold(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 6); + + proto_tree_add_item(tree, hf_lmp_htime, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_hinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); +} + +void +dissect_hold_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 6); + + proto_tree_add_item(tree, hf_lmp_htime, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_hinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); +} + +void +dissect_sniff_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 10); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 9); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_dsniff, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_tsniff, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffatt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffto, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_unsniff_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_park_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_tb, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nb, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_deltab, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_araddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_nbsleep, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_dbsleep, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_daccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_taccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_naccslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_npoll, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_accscheme, tvb, offset, 1, ENC_NA); +} + +void +dissect_set_broadcast_scan_window(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 6); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 4); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + } + + proto_tree_add_item(tree, hf_lmp_bsw, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_modify_beacon(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 13); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 11); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 11); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 9); + } + + proto_tree_add_item(tree, hf_lmp_tb, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nb, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_deltab, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_daccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_taccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_naccslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_npoll, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_accscheme, tvb, offset, 1, ENC_NA); +} + +void +dissect_unpark_bd_addr_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + proto_item *item; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 15); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 15); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 13); + } + + proto_tree_add_item(tree, hf_lmp_ltaddr1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_bdaddr1, tvb, offset, 6, ENC_LITTLE_ENDIAN); + offset += 6; + + proto_tree_add_item(tree, hf_lmp_bdaddr2, tvb, offset, 6, ENC_LITTLE_ENDIAN); + offset += 6; +} + +void +dissect_unpark_pm_addr_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 15); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 13); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 13); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 11); + } + + proto_tree_add_item(tree, hf_lmp_ltaddr1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_ltaddr3, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr4, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr3, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr4, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_ltaddr5, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr6, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr5, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr6, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_ltaddr7, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr7, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_incr_power_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + + /* skipping one byte "for future use" */ +} + +void +dissect_decr_power_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + + /* skipping one byte "for future use" */ +} + +void +dissect_max_power(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_min_power(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_auto_rate(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_preferred_rate(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + proto_item *rate_item; + proto_tree *rate_tree; + + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + rate_item = proto_tree_add_item(tree, hf_lmp_rate, tvb, offset, 1, ENC_LITTLE_ENDIAN); + rate_tree = proto_item_add_subtree(rate_item, ett_lmp_rate); + + proto_tree_add_item(rate_tree, hf_lmp_rate_fec, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(rate_tree, hf_lmp_rate_size, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(rate_tree, hf_lmp_rate_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(rate_tree, hf_lmp_rate_edrsize, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_version_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 6); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 5); + + proto_tree_add_item(tree, hf_lmp_versnr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_compid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_subversnr, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_version_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 6); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 5); + + proto_tree_add_item(tree, hf_lmp_versnr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_compid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_subversnr, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_features_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 8); + + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_features_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 8); + + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_quality_of_service(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_pollintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nbc, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_quality_of_service_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_pollintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nbc, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_sco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 6); + + proto_tree_add_item(tree, hf_lmp_scohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_dsco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_tsco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_scopkt, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_airmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_remove_sco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_scohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_max_slot(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_maxslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_max_slot_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_maxslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_timing_accuracy_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_timing_accuracy_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_drift, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_jitter, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_setup_complete(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_use_semi_permanent_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_host_connection_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_slot_offset(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 8); + + proto_tree_add_item(tree, hf_lmp_slotoffset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_bdaddr, tvb, offset, 6, ENC_LITTLE_ENDIAN); +} + +void +dissect_page_mode_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_pagesch, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pssettings, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_page_scan_mode_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_pagesch, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pssettings, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_supervision_timeout(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_suptimeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_test_activate(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_test_control(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 10); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 9); + + /* FIXME these fields should all be XORed with 0x55. . . */ + + proto_tree_add_item(tree, hf_lmp_testscen, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_hopmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_txfreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_rxfreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pcmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pollper, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pkttype, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_testlen, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_encryption_key_size_mask_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_encryption_key_size_mask_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_ksmask, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_set_afh(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 16); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 15); + + proto_tree_add_item(tree, hf_lmp_afhinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_lmp_afhmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_afhchmap, tvb, offset, 10, ENC_NA); +} + +void +dissect_encapsulated_header(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_encmaj, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_encmin, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_enclen, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_encapsulated_payload(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_encdata, tvb, offset, 16, ENC_NA); +} + +void +dissect_simple_pairing_confirm(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_commit, tvb, offset, 16, ENC_NA); +} + +void +dissect_simple_pairing_number(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_nonce, tvb, offset, 16, ENC_NA); +} + +void +dissect_dhkey_check(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_confirm, tvb, offset, 16, ENC_NA); +} + +/* LMP PDUs with extended opcodes */ + +void +dissect_accepted_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_eopinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_not_accepted_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_eopinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_features_req_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 12); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 10); + + proto_tree_add_item(tree, hf_lmp_fpage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maxsp, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* + * extended features might need to be different from hf_lmp_features + * if hf_lmp_features is broken out + */ + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_features_res_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 12); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 10); + + proto_tree_add_item(tree, hf_lmp_fpage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maxsp, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* + * extended features might need to be different from hf_lmp_features + * if hf_lmp_features is broken out + */ + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_packet_type_table_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_pkttypetbl, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_esco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 16); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 14); + + proto_tree_add_item(tree, hf_lmp_escohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escoltaddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_desco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_tesco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_wesco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escotypems, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escotypesm, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escolenms, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_escolensm, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_airmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_negstate, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_remove_esco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_escohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_channel_classification_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 5); + + proto_tree_add_item(tree, hf_lmp_afhrptmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_afhminintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_afhmaxintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_channel_classification(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 12); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 10); + + proto_tree_add_item(tree, hf_lmp_afhclass, tvb, offset, 10, ENC_NA); +} + +void +dissect_sniff_subrating_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 7); + + proto_tree_add_item(tree, hf_lmp_maxss, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_minsmt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffsi, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_sniff_subrating_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 7); + + proto_tree_add_item(tree, hf_lmp_maxss, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_minsmt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffsi, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_pause_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_resume_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_io_capability_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_iocaps, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_oobauthdata, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_authreqs, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_io_capability_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_iocaps, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_oobauthdata, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_authreqs, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_numeric_comparison_failed(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_passkey_failed(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_oob_failed(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_keypress_notification(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_nottype, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_power_control_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_pwradjreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_power_control_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + proto_item *pa_item; + proto_tree *pa_tree; + + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + pa_item = proto_tree_add_item(tree, hf_lmp_pwradjres, tvb, offset, 1, ENC_LITTLE_ENDIAN); + pa_tree = proto_item_add_subtree(pa_item, ett_lmp_pwradjres); + + proto_tree_add_item(pa_tree, hf_lmp_pwradj_gfsk, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pa_tree, hf_lmp_pwradj_dqpsk, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pa_tree, hf_lmp_pwradj_8dpsk, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +/* Link Manager Protocol */ +static void +dissect_btbrlmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *lmp_item; + proto_tree *lmp_tree; + int offset; + int len; + int op; /* opcode */ + int eop; /* extended opcode */ + + offset = 0; + len = tvb_length(tvb); + + DISSECTOR_ASSERT(len >= 1); + + /* make entries in protocol column and info column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LMP"); + + /* clear the info column first just in case of type fetching failure. */ + col_clear(pinfo->cinfo, COL_INFO); + + op = tvb_get_guint8(tvb, offset) >> 1; + + if (op == LMP_ESCAPE_4) { + DISSECTOR_ASSERT(len >= 2); + + eop = tvb_get_guint8(tvb, offset + 1); + + col_add_str(pinfo->cinfo, COL_INFO, val_to_str(eop, + opcode, "Unknown Extended Opcode (%d)")); + } else { + col_add_str(pinfo->cinfo, COL_INFO, val_to_str(op, + opcode, "Unknown Opcode (%d)")); + } + + /* see if we are being asked for details */ + if (!tree) + return; + + lmp_item = proto_tree_add_item(tree, proto_btbrlmp, tvb, offset, -1, ENC_NA); + lmp_tree = proto_item_add_subtree(lmp_item, ett_lmp); + + proto_tree_add_item(lmp_tree, hf_lmp_tid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(lmp_tree, hf_lmp_op, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + switch (op) { + case LMP_NAME_REQ: + dissect_name_req(lmp_tree, tvb, offset, len); + break; + case LMP_NAME_RES: + dissect_name_res(lmp_tree, tvb, offset, len); + break; + case LMP_ACCEPTED: + dissect_accepted(lmp_tree, tvb, offset, len); + break; + case LMP_NOT_ACCEPTED: + dissect_not_accepted(lmp_tree, tvb, offset, len); + break; + case LMP_CLKOFFSET_REQ: + dissect_clkoffset_req(lmp_tree, tvb, offset, len); + break; + case LMP_CLKOFFSET_RES: + dissect_clkoffset_res(lmp_tree, tvb, offset, len); + break; + case LMP_DETACH: + dissect_detach(lmp_tree, tvb, offset, len); + break; + case LMP_IN_RAND: + dissect_in_rand(lmp_tree, tvb, offset, len); + break; + case LMP_COMB_KEY: + dissect_comb_key(lmp_tree, tvb, offset, len); + break; + case LMP_UNIT_KEY: + dissect_unit_key(lmp_tree, tvb, offset, len); + break; + case LMP_AU_RAND: + dissect_au_rand(lmp_tree, tvb, offset, len); + break; + case LMP_SRES: + dissect_sres(lmp_tree, tvb, offset, len); + break; + case LMP_TEMP_RAND: + dissect_temp_rand(lmp_tree, tvb, offset, len); + break; + case LMP_TEMP_KEY: + dissect_temp_key(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_MODE_REQ: + dissect_encryption_mode_req(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_KEY_SIZE_REQ: + dissect_encryption_key_size_req(lmp_tree, tvb, offset, len); + break; + case LMP_START_ENCRYPTION_REQ: + dissect_start_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_STOP_ENCRYPTION_REQ: + dissect_stop_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_SWITCH_REQ: + dissect_switch_req(lmp_tree, tvb, offset, len); + break; + case LMP_HOLD: + dissect_hold(lmp_tree, tvb, offset, len); + break; + case LMP_HOLD_REQ: + dissect_hold_req(lmp_tree, tvb, offset, len); + break; + case LMP_SNIFF_REQ: + dissect_sniff_req(lmp_tree, tvb, offset, len); + break; + case LMP_UNSNIFF_REQ: + dissect_unsniff_req(lmp_tree, tvb, offset, len); + break; + case LMP_PARK_REQ: + dissect_park_req(lmp_tree, tvb, offset, len); + break; + case LMP_SET_BROADCAST_SCAN_WINDOW: + dissect_set_broadcast_scan_window(lmp_tree, tvb, offset, len); + break; + case LMP_MODIFY_BEACON: + dissect_modify_beacon(lmp_tree, tvb, offset, len); + break; + case LMP_UNPARK_BD_ADDR_REQ: + dissect_unpark_bd_addr_req(lmp_tree, tvb, offset, len); + break; + case LMP_UNPARK_PM_ADDR_REQ: + dissect_unpark_pm_addr_req(lmp_tree, tvb, offset, len); + break; + case LMP_INCR_POWER_REQ: + dissect_incr_power_req(lmp_tree, tvb, offset, len); + break; + case LMP_DECR_POWER_REQ: + dissect_decr_power_req(lmp_tree, tvb, offset, len); + break; + case LMP_MAX_POWER: + dissect_max_power(lmp_tree, tvb, offset, len); + break; + case LMP_MIN_POWER: + dissect_min_power(lmp_tree, tvb, offset, len); + break; + case LMP_AUTO_RATE: + dissect_auto_rate(lmp_tree, tvb, offset, len); + break; + case LMP_PREFERRED_RATE: + dissect_preferred_rate(lmp_tree, tvb, offset, len); + break; + case LMP_VERSION_REQ: + dissect_version_req(lmp_tree, tvb, offset, len); + break; + case LMP_VERSION_RES: + dissect_version_res(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_REQ: + dissect_features_req(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_RES: + dissect_features_res(lmp_tree, tvb, offset, len); + break; + case LMP_QUALITY_OF_SERVICE: + dissect_quality_of_service(lmp_tree, tvb, offset, len); + break; + case LMP_QUALITY_OF_SERVICE_REQ: + dissect_quality_of_service_req(lmp_tree, tvb, offset, len); + break; + case LMP_SCO_LINK_REQ: + dissect_sco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_REMOVE_SCO_LINK_REQ: + dissect_remove_sco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_MAX_SLOT: + dissect_max_slot(lmp_tree, tvb, offset, len); + break; + case LMP_MAX_SLOT_REQ: + dissect_max_slot_req(lmp_tree, tvb, offset, len); + break; + case LMP_TIMING_ACCURACY_REQ: + dissect_timing_accuracy_req(lmp_tree, tvb, offset, len); + break; + case LMP_TIMING_ACCURACY_RES: + dissect_timing_accuracy_res(lmp_tree, tvb, offset, len); + break; + case LMP_SETUP_COMPLETE: + dissect_setup_complete(lmp_tree, tvb, offset, len); + break; + case LMP_USE_SEMI_PERMANENT_KEY: + dissect_use_semi_permanent_key(lmp_tree, tvb, offset, len); + break; + case LMP_HOST_CONNECTION_REQ: + dissect_host_connection_req(lmp_tree, tvb, offset, len); + break; + case LMP_SLOT_OFFSET: + dissect_slot_offset(lmp_tree, tvb, offset, len); + break; + case LMP_PAGE_MODE_REQ: + dissect_page_mode_req(lmp_tree, tvb, offset, len); + break; + case LMP_PAGE_SCAN_MODE_REQ: + dissect_page_scan_mode_req(lmp_tree, tvb, offset, len); + break; + case LMP_SUPERVISION_TIMEOUT: + dissect_supervision_timeout(lmp_tree, tvb, offset, len); + break; + case LMP_TEST_ACTIVATE: + dissect_test_activate(lmp_tree, tvb, offset, len); + break; + case LMP_TEST_CONTROL: + dissect_test_control(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_KEY_SIZE_MASK_REQ: + dissect_encryption_key_size_mask_req(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_KEY_SIZE_MASK_RES: + dissect_encryption_key_size_mask_res(lmp_tree, tvb, offset, len); + break; + case LMP_SET_AFH: + dissect_set_afh(lmp_tree, tvb, offset, len); + break; + case LMP_ENCAPSULATED_HEADER: + dissect_encapsulated_header(lmp_tree, tvb, offset, len); + break; + case LMP_ENCAPSULATED_PAYLOAD: + dissect_encapsulated_payload(lmp_tree, tvb, offset, len); + break; + case LMP_SIMPLE_PAIRING_CONFIRM: + dissect_simple_pairing_confirm(lmp_tree, tvb, offset, len); + break; + case LMP_SIMPLE_PAIRING_NUMBER: + dissect_simple_pairing_number(lmp_tree, tvb, offset, len); + break; + case LMP_DHKEY_CHECK: + dissect_dhkey_check(lmp_tree, tvb, offset, len); + break; + case LMP_ESCAPE_1: + break; + case LMP_ESCAPE_2: + break; + case LMP_ESCAPE_3: + break; + case LMP_ESCAPE_4: + /* extended opcode */ + DISSECTOR_ASSERT(len >= 2); + proto_tree_add_item(lmp_tree, hf_lmp_eop, tvb, offset, 1, ENC_NA); + offset += 1; + + switch (eop) { + case LMP_ACCEPTED_EXT: + dissect_accepted_ext(lmp_tree, tvb, offset, len); + break; + case LMP_NOT_ACCEPTED_EXT: + dissect_not_accepted_ext(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_REQ_EXT: + dissect_features_req_ext(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_RES_EXT: + dissect_features_res_ext(lmp_tree, tvb, offset, len); + break; + case LMP_PACKET_TYPE_TABLE_REQ: + dissect_packet_type_table_req(lmp_tree, tvb, offset, len); + break; + case LMP_ESCO_LINK_REQ: + dissect_esco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_REMOVE_ESCO_LINK_REQ: + dissect_remove_esco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_CHANNEL_CLASSIFICATION_REQ: + dissect_channel_classification_req(lmp_tree, tvb, offset, len); + break; + case LMP_CHANNEL_CLASSIFICATION: + dissect_channel_classification(lmp_tree, tvb, offset, len); + break; + case LMP_SNIFF_SUBRATING_REQ: + dissect_sniff_subrating_req(lmp_tree, tvb, offset, len); + break; + case LMP_SNIFF_SUBRATING_RES: + dissect_sniff_subrating_res(lmp_tree, tvb, offset, len); + break; + case LMP_PAUSE_ENCRYPTION_REQ: + dissect_pause_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_RESUME_ENCRYPTION_REQ: + dissect_resume_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_IO_CAPABILITY_REQ: + dissect_io_capability_req(lmp_tree, tvb, offset, len); + break; + case LMP_IO_CAPABILITY_RES: + dissect_io_capability_res(lmp_tree, tvb, offset, len); + break; + case LMP_NUMERIC_COMPARISON_FAILED: + dissect_numeric_comparison_failed(lmp_tree, tvb, offset, len); + break; + case LMP_PASSKEY_FAILED: + dissect_passkey_failed(lmp_tree, tvb, offset, len); + break; + case LMP_OOB_FAILED: + dissect_oob_failed(lmp_tree, tvb, offset, len); + break; + case LMP_KEYPRESS_NOTIFICATION: + dissect_keypress_notification(lmp_tree, tvb, offset, len); + break; + case LMP_POWER_CONTROL_REQ: + dissect_power_control_req(lmp_tree, tvb, offset, len); + break; + case LMP_POWER_CONTROL_RES: + dissect_power_control_res(lmp_tree, tvb, offset, len); + break; + default: + break; + } + default: + break; + } +}; + +/* register the protocol with Wireshark */ +void +proto_register_btbrlmp(void) +{ + + /* list of fields */ + static hf_register_info hf[] = { + { &hf_lmp_accscheme, + { "Access Scheme", "btbrlmp.accscheme", + FT_UINT8, BASE_DEC, VALS(access_scheme), 0xf0, + NULL, HFILL } + }, + { &hf_lmp_afhchmap, + { "AFH Channel Map", "btbrlmp.afhchmap", + /* could break out individual channels but long */ + FT_BYTES, BASE_NONE, NULL, 0x0, + "Adaptive Frequency Hopping Channel Map", HFILL } + }, + { &hf_lmp_afhclass, + { "AFH Channel Classification", "btbrlmp.afhclass", + /* could break out individual channels but long */ + FT_BYTES, BASE_NONE, NULL, 0x0, + "Adaptive Frequency Hopping Channel Classification", HFILL } + }, + { &hf_lmp_afhinst, + { "AFH Instant", "btbrlmp.afhinst", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Adaptive Frequency Hopping Instant (slot)", HFILL } + }, + { &hf_lmp_afhmaxintvl, + { "AFH Max Interval", "btbrlmp.maxintvl", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Adaptive Maximum Interval in slots", HFILL } + }, + { &hf_lmp_afhminintvl, + { "AFH Min Interval", "btbrlmp.minintvl", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Adaptive Minimum Interval in slots", HFILL } + }, + { &hf_lmp_afhmode, + { "AFH Mode", "btbrlmp.afhmode", + FT_UINT8, BASE_DEC, VALS(afh_mode), 0x0, + "Adaptive Frequency Hopping Mode", HFILL } + }, + { &hf_lmp_afhrptmode, + { "AFH Reporting Mode", "btbrlmp.afhrptmode", + FT_UINT8, BASE_DEC, VALS(afh_reporting_mode), 0x0, + "Adaptive Frequency Hopping Reporting Mode", HFILL } + }, + { &hf_lmp_airmode, + { "Air Mode", "btbrlmp.airmode", + FT_UINT8, BASE_HEX, VALS(air_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_araddr, + { "AR_ADDR", "btbrlmp.araddr", + FT_UINT8, BASE_HEX, NULL, 0xfe, + NULL, HFILL } + }, + { &hf_lmp_authreqs, + { "Authentication Requirements", "btbrlmp.authreqs", + FT_UINT8, BASE_HEX, VALS(auth_requirements), 0xf0, + NULL, HFILL } + }, + { &hf_lmp_authres, + { "Authentication Response", "btbrlmp.authres", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_bdaddr, + { "BD_ADDR", "btbrlmp.bdaddr", + FT_UINT64, BASE_HEX, NULL, 0x0000ffffffffffff, + NULL, HFILL } + }, + { &hf_lmp_bdaddr1, + { "BD_ADDR 1", "btbrlmp.bdaddr", + FT_UINT64, BASE_HEX, NULL, 0x0000ffffffffffff, + NULL, HFILL } + }, + { &hf_lmp_bdaddr2, + { "BD_ADDR2", "btbrlmp.bdaddr", + FT_UINT64, BASE_HEX, NULL, 0x0000ffffffffffff, + "BD_ADDR 2", HFILL } + }, + { &hf_lmp_bsw, + { "Broadcast Scan Window", "btbrlmp.bsw", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Broadcast Scan Window in slots", HFILL } + }, + { &hf_lmp_clkoffset, + { "Clock Offset", "btbrlmp.clkoffset", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Clock Offset in units of 1.25 ms", HFILL } + }, + { &hf_lmp_commit, + { "Commitment Value", "btbrlmp.commit", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_confirm, + { "Confirmation Value", "btbrlmp.confirm", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_compid, + { "Company ID", "btbrlmp.compid", + FT_UINT16, BASE_DEC, VALS(compid), 0x0, + NULL, HFILL } + }, + { &hf_lmp_cryptmode, + { "Encryption Mode", "btbrlmp.cryptmode", + FT_UINT8, BASE_DEC, VALS(encryption_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_daccess, + { "Daccess", "btbrlmp.daccess", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Daccess in slots", HFILL } + }, + { &hf_lmp_db, + { "Db", "btbrlmp.db", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Db in slots", HFILL } + }, + { &hf_lmp_dbsleep, + { "Dbsleep", "btbrlmp.dbsleep", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_deltab, + { "Deltab", "btbrlmp.deltab", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Deltab in slots", HFILL } + }, + { &hf_lmp_desco, + { "Desco", "btbrlmp.desco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Desco in slots", HFILL } + }, + { &hf_lmp_drift, + { "Drift", "btbrlmp.drift", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Drift in ppm", HFILL } + }, + { &hf_lmp_dsco, + { "Dsco", "btbrlmp.dsco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Dsco in slots", HFILL } + }, + { &hf_lmp_dsniff, + { "Dsniff", "btbrlmp.dsniff", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Dsniff in slots", HFILL } + }, + { &hf_lmp_encdata, + { "Encapsulated Data", "btbrlmp.encdata", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_enclen, + { "Encapsulated Length", "btbrlmp.enclen", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_encmaj, + { "Encapsulated Major Type", "btbrlmp.encmaj", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_encmin, + { "Encapsulated Minor Type", "btbrlmp.encmin", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_eop, + { "Extended Opcode", "btbrlmp.eop", + FT_UINT8, BASE_DEC, VALS(ext_opcode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_eopinre, + { "In Response To", "btbrlmp.eopinre", + FT_UINT8, BASE_DEC, VALS(ext_opcode), 0x0, + "Extended Opcode this is in response to", HFILL } + }, + { &hf_lmp_escolenms, + { "Packet Length M -> S", "btbrlmp.escolenms", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Packet Length in bytes Master to Slave", HFILL } + }, + { &hf_lmp_escolensm, + { "Packet Length S -> M", "btbrlmp.escolensm", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Packet Length in bytes Slave to Master", HFILL } + }, + { &hf_lmp_escotypems, + { "eSCO Packet Type M -> S", "btbrlmp.escotypems", + FT_UINT8, BASE_HEX, VALS(esco_packet_type), 0x0, + "eSCO Packet Type Master to Slave", HFILL } + }, + { &hf_lmp_escotypesm, + { "eSCO Packet Type S -> M", "btbrlmp.escotypesm", + FT_UINT8, BASE_HEX, VALS(esco_packet_type), 0x0, + "eSCO Packet Type Slave to Master", HFILL } + }, + { &hf_lmp_err, + { "Error Code", "btbrlmp.err", + FT_UINT8, BASE_HEX, VALS(error_code), 0x0, + NULL, HFILL } + }, + { &hf_lmp_escohdl, + { "eSCO Handle", "btbrlmp.escohdl", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_escoltaddr, + { "eSCO LT_ADDR", "btbrlmp.escoltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0, + "eSCO Logical Transport Address", HFILL } + }, + { &hf_lmp_features, + { "Features", "btbrlmp.features", + /* could break out individual features but long */ + FT_BYTES, BASE_NONE, NULL, 0x0, + "Feature Mask", HFILL } + }, + { &hf_lmp_fpage, + { "Features Page", "btbrlmp.fpage", + FT_UINT8, BASE_DEC, VALS(features_page), 0x0, + NULL, HFILL } + }, + { &hf_lmp_htime, + { "Hold Time", "btbrlmp.htime", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Hold Time in slots", HFILL } + }, + { &hf_lmp_hinst, + { "Hold Instant", "btbrlmp.hinst", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Hold Instant (slot)", HFILL } + }, + { &hf_lmp_hopmode, + { "Hopping Mode", "btbrlmp.hopmode", + FT_UINT8, BASE_DEC, VALS(hopping_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_iocaps, + { "IO Capabilities", "btbrlmp.iocaps", + FT_UINT8, BASE_DEC, VALS(io_capabilities), 0x0, + "Input/Output Capabilities", HFILL } + }, + { &hf_lmp_jitter, + { "Jitter", "btbrlmp.jitter", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Jitter in microseconds", HFILL } + }, + { &hf_lmp_key, + { "Key", "btbrlmp.key", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_keysz, + { "Key Size", "btbrlmp.keysz", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Key Size in bytes", HFILL } + }, + { &hf_lmp_ksmask, + { "Key Size Mask", "btbrlmp.ksmask", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_ltaddr1, + { "LT_ADDR 1", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 1", HFILL } + }, + { &hf_lmp_ltaddr2, + { "LT_ADDR 2", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Logical Transport Address 2", HFILL } + }, + { &hf_lmp_ltaddr3, + { "LT_ADDR 3", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 3", HFILL } + }, + { &hf_lmp_ltaddr4, + { "LT_ADDR 4", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Logical Transport Address 4", HFILL } + }, + { &hf_lmp_ltaddr5, + { "LT_ADDR 5", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 5", HFILL } + }, + { &hf_lmp_ltaddr6, + { "LT_ADDR 6", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Logical Transport Address 6", HFILL } + }, + { &hf_lmp_ltaddr7, + { "LT_ADDR 7", "btbrlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 7", HFILL } + }, + { &hf_lmp_maccess, + { "Maccess", "btbrlmp.maccess", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Number of access windows", HFILL } + }, + { &hf_lmp_maxslots, + { "Max Slots", "btbrlmp.maxslots", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_maxsp, + { "Max Supported Page", "btbrlmp.maxsp", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Highest extended features page with non-zero bit", HFILL } + }, + { &hf_lmp_maxss, + { "Max Sniff Subrate", "btbrlmp.maxss", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_minsmt, + { "Min Sniff Mode Timeout", "btbrlmp.minsmt", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Min Sniff Mode Timeout in slots", HFILL } + }, + { &hf_lmp_naccslots, + { "Nacc-slots", "btbrlmp.naccslots", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_namefrag, + { "Name Fragment", "btbrlmp.namefrag", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_namelen, + { "Name Length", "btbrlmp.namelen", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Name Length in bytes", HFILL } + }, + { &hf_lmp_nameoffset, + { "Name Offset", "btbrlmp.nameoffset", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Name Offset in bytes", HFILL } + }, + { &hf_lmp_nb, + { "Nb", "btbrlmp.nb", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_nbc, + { "Nbc", "btbrlmp.nbc", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_nbsleep, + { "Nbsleep", "btbrlmp.nbsleep", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_negstate, + { "Negotiation State", "btbrlmp.negstate", + FT_UINT8, BASE_DEC, VALS(negotiation_state), 0x0, + NULL, HFILL } + }, + { &hf_lmp_nonce, + { "Nonce Value", "btbrlmp.nonce", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_nottype, + { "Notification Type", "btbrlmp.nottype", + FT_UINT8, BASE_DEC, VALS(notification_value), 0x0, + NULL, HFILL } + }, + { &hf_lmp_npoll, + { "Npoll", "btbrlmp.npoll", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_oobauthdata, + { "OOB Authentication Data", "btbrlmp.oobauthdata", + FT_UINT8, BASE_DEC, VALS(oob_auth_data), 0xfe, + NULL, HFILL } + }, + { &hf_lmp_op, + { "Opcode", "btbrlmp.op", + FT_UINT8, BASE_DEC, VALS(opcode), 0xfe, + NULL, HFILL } + }, + { &hf_lmp_opinre, + { "In Response To", "btbrlmp.opinre", + FT_UINT8, BASE_DEC, VALS(opcode), 0x7f, + "Opcode this is in response to", HFILL } + }, + { &hf_lmp_pagesch, + { "Paging Scheme", "btbrlmp.pagesch", + FT_UINT8, BASE_DEC, VALS(paging_scheme), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pcmode, + { "Power Control Mode", "btbrlmp.pcmode", + FT_UINT8, BASE_DEC, VALS(power_control_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pkttype, + { "Packet Type", "btbrlmp.pkttype", + /* FIXME break out further */ + FT_UINT8, BASE_HEX, NULL, 0x0, + "Packet Type", HFILL } + }, + { &hf_lmp_pkttypetbl, + { "Packet Type Table", "btbrlmp.pkttypetbl", + FT_UINT8, BASE_DEC, VALS(packet_type_table), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr, + { "PM_ADDR", "btbrlmp.pmaddr", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr1, + { "PM_ADDR 1", "btbrlmp.pmaddr1", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr2, + { "PM_ADDR 2", "btbrlmp.pmaddr2", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr3, + { "PM_ADDR 3", "btbrlmp.pmaddr3", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr4, + { "PM_ADDR 4", "btbrlmp.pmaddr4", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr5, + { "PM_ADDR 5", "btbrlmp.pmaddr5", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr6, + { "PM_ADDR 6", "btbrlmp.pmaddr6", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr7, + { "PM_ADDR 7", "btbrlmp.pmaddr7", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pollintvl, + { "Poll Interval", "btbrlmp.pollintvl", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Poll Interval in slots", HFILL } + }, + { &hf_lmp_pollper, + { "Poll Period", "btbrlmp.pollper", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Poll Period in units of 1.25 ms", HFILL } + }, + { &hf_lmp_pssettings, + { "Paging Scheme Settings", "btbrlmp.pssettings", + FT_UINT8, BASE_DEC, VALS(paging_scheme_settings), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pwradjreq, + { "Power Adjustment Request", "btbrlmp.pwradjreq", + FT_UINT8, BASE_DEC, VALS(power_adjust_req), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pwradjres, + { "Power Adjustment Response", "btbrlmp.pwradjres", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pwradj_8dpsk, + { "8DPSK", "btbrlmp.pwradj_8dpsk", + FT_UINT8, BASE_DEC, VALS(power_adjust_res), 0x30, + "8DPSK Power Adjustment Response", HFILL } + }, + { &hf_lmp_pwradj_dqpsk, + { "DQPSK", "btbrlmp.pwradj_dqpsk", + FT_UINT8, BASE_DEC, VALS(power_adjust_res), 0x0C, + "DQPSK Power Adjustment Response", HFILL } + }, + { &hf_lmp_pwradj_gfsk, + { "GFSK", "btbrlmp.pwradj_gfsk", + FT_UINT8, BASE_DEC, VALS(power_adjust_res), 0x03, + "GFSK Power Adjustment Response", HFILL } + }, + { &hf_lmp_rand, + { "Random Number", "btbrlmp.rand", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_rate, + { "Data Rate", "btbrlmp.rate", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_rate_fec, + { "FEC", "btbrlmp.rate.fec", + FT_BOOLEAN, BASE_DEC, TFS(&fec), 0x01, + "Forward Error Correction", HFILL } + }, + { &hf_lmp_rate_size, + { "Packet Size", "btbrlmp.rate.size", + FT_UINT8, BASE_HEX, VALS(packet_size), 0x06, + "Basic Rate Packet Size", HFILL } + }, + { &hf_lmp_rate_type, + { "EDR Type", "btbrlmp.rate.type", + FT_UINT8, BASE_HEX, VALS(edr_type), 0x18, + "Enhanced Data Rate type", HFILL } + }, + { &hf_lmp_rate_edrsize, + { "EDR Size", "btbrlmp.rate.edrsize", + FT_UINT8, BASE_HEX, VALS(packet_size), 0x60, + "Enhanced Data Rate packet size", HFILL } + }, + { &hf_lmp_rxfreq, + { "RX Frequency", "btbrlmp.rxfreq", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Receive Frequency in MHz above 2402", HFILL } + }, + { &hf_lmp_scohdl, + { "SCO Handle", "btbrlmp.scohdl", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_scopkt, + { "SCO Packet", "btbrlmp.scopkt", + FT_UINT8, BASE_DEC, VALS(sco_packet), 0x0, + NULL, HFILL } + }, + { &hf_lmp_slotoffset, + { "Slot Offset", "btbrlmp.slotoffset", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Slot Offset in microseconds", HFILL } + }, + { &hf_lmp_sniffatt, + { "Sniff Attempt", "btbrlmp.sniffatt", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Number of receive slots", HFILL } + }, + { &hf_lmp_sniffsi, + { "Sniff Subrating Instant", "btbrlmp.sniffsi", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Sniff Subrating Instant (slot)", HFILL } + }, + { &hf_lmp_sniffto, + { "Sniff Timeout", "btbrlmp.sniffto", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Number of receive slots", HFILL } + }, + { &hf_lmp_subversnr, + { "SubVersNr", "btbrlmp.subversnr", + FT_UINT16, BASE_DEC, NULL, 0x0, + "SubVersion", HFILL } + }, + { &hf_lmp_suptimeout, + { "Supervision Timeout", "btbrlmp.suptimeout", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Supervision Timeout in slots", HFILL } + }, + { &hf_lmp_swinst, + { "Switch Instant", "btbrlmp.swinst", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Switch Instant (slot)", HFILL } + }, + { &hf_lmp_taccess, + { "Taccess", "btbrlmp.taccess", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Taccess in slots", HFILL } + }, + { &hf_lmp_tb, + { "Tb", "btbrlmp.tb", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Tb in slots", HFILL } + }, + { &hf_lmp_tesco, + { "Tesco", "btbrlmp.tesco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Tesco in slots", HFILL } + }, + { &hf_lmp_testlen, + { "Test Length", "btbrlmp.testlen", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of test sequence in bytes", HFILL } + }, + { &hf_lmp_testscen, + { "Test Scenario", "btbrlmp.testscen", + FT_UINT8, BASE_DEC, VALS(test_scenario), 0x0, + NULL, HFILL } + }, + { &hf_lmp_tid, + { "TID", "btbrlmp.tid", + FT_BOOLEAN, BASE_DEC, TFS(&tid), 0x01, + "Transaction ID", HFILL } + }, + { &hf_lmp_timectrl, + { "Timing Control Flags", "btbrlmp.timectrl", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_time_change, + { "Timing Change", "btbrlmp.time.change", + FT_BOOLEAN, 8, TFS(&time_change), 0x01, + NULL, HFILL } + }, + { &hf_lmp_time_init, + { "Initialization", "btbrlmp.time.init", + FT_BOOLEAN, 8, TFS(&time_init), 0x02, + NULL, HFILL } + }, + { &hf_lmp_time_accwin, + { "Access Window", "btbrlmp.time.accwin", + FT_BOOLEAN, 8, TFS(&time_accwin), 0x04, + NULL, HFILL } + }, + { &hf_lmp_tsco, + { "Tsco", "btbrlmp.tsco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Tsco in slots", HFILL } + }, + { &hf_lmp_tsniff, + { "Tsniff", "btbrlmp.tsniff", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Tsniff in slots", HFILL } + }, + { &hf_lmp_txfreq, + { "TX Frequency", "btbrlmp.txfreq", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Transmit Frequency in MHz above 2402", HFILL } + }, + { &hf_lmp_versnr, + { "VersNr", "btbrlmp.versnr", + FT_UINT8, BASE_DEC, VALS(versnr), 0x0, + "Version", HFILL } + }, + { &hf_lmp_wesco, + { "Wesco", "btbrlmp.wesco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Number of slots in retransmission window", HFILL } + }, + }; + + /* protocol subtree arrays */ + static gint *ett[] = { + &ett_lmp, + &ett_lmp_pwradjres, + &ett_lmp_rate, + &ett_lmp_timectrl, + }; + + /* register the protocol name and description */ + proto_btbrlmp = proto_register_protocol( + "Bluetooth BR Link Manager Protocol", /* full name */ + "btbrlmp", /* short name */ + "btbrlmp" /* abbreviation (e.g. for filters) */ + ); + + register_dissector("btbrlmp", dissect_btbrlmp, proto_btbrlmp); + + /* register the header fields and subtrees used */ + proto_register_field_array(proto_btbrlmp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_reg_handoff_btbrlmp(void) +{ +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/plugin.rc.in b/libbtbb-2015-10-R1/wireshark/plugins/btbb/plugin.rc.in new file mode 100644 index 0000000..568dc07 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/plugin.rc.in @@ -0,0 +1,34 @@ +#include "winver.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @RC_MODULE_VERSION@ + PRODUCTVERSION @RC_VERSION@ + FILEFLAGSMASK 0x0L +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0" + VALUE "FileDescription", "@PACKAGE@ dissector\0" + VALUE "FileVersion", "@MODULE_VERSION@\0" + VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0" + VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs , Gilbert Ramirez and others\0" + VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0" + VALUE "ProductName", "Wireshark\0" + VALUE "ProductVersion", "@VERSION@\0" + VALUE "Comments", "Build with @MSVC_VARIANT@\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg b/libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg new file mode 100755 index 0000000..d2efa7c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg.py b/libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg.py new file mode 100755 index 0000000..060460c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbb/tools/make-dissector-reg.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $ + +import os +import sys +import re +import pickle +from stat import * + +VERSION_KEY = '_VERSION' +CUR_VERSION = '$Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $' + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin" or registertype == "plugin_wtap": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by Makefile or Makefile.nmake. + */ +""" +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by the "register.c" target in + * epan/dissectors/Makefile or Makefile.nmake using information in + * epan/dissectors/register-cache.pkl. + * + * You can force this file to be regenerated completely by deleting + * it along with epan/dissectors/register-cache.pkl. + */ +""" +else: + print(("Unknown output type '%s'" % registertype)) + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append(os.path.join(srcdir, file)) + +if len(filenames) < 1: + print("No files found") + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +wtap_reg_regex0 = r"^(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" +wtap_reg_regex1 = r"void\s+(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ( 'wtap_register', re.compile(wtap_reg_regex0) ), + ( 'wtap_register', re.compile(wtap_reg_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION: + cache = {VERSION_KEY: CUR_VERSION} + except: + cache = {VERSION_KEY: CUR_VERSION} + + print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1))) + +# Grep +cache_hits = 0 +cache_misses = 0 +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and filename in cache: + cdict = cache[filename] + if cur_mtime == cdict['mtime']: + cache_hits += 1 +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + regs['wtap_register'].extend(cdict['wtap_register']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache_misses += 1 + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses))) + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print("No protocol registrations found") + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() +regs['wtap_register'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write(preamble) + +# Make the routine to register all protocols +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +elif registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +register_wtap_module(void) +{ +"""); + + for symbol in regs['wtap_register']: + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + reg_code.write(line) + + reg_code.write("}\n"); + reg_code.write("#endif\n"); +else: + reg_code.write(""" +static gulong proto_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['proto_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +static gulong handoff_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['handoff_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return proto_reg_count() + handoff_reg_count();" + reg_code.write(line) + + reg_code.write(""" +}\n +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/AUTHORS b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/AUTHORS new file mode 100644 index 0000000..b127790 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/AUTHORS @@ -0,0 +1,3 @@ +Authors: +Michael Ossmann +Dominic Spill diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/CMakeLists.txt b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/CMakeLists.txt new file mode 100644 index 0000000..2bc4948 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/CMakeLists.txt @@ -0,0 +1,86 @@ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +project(btbredr-wireshark-plugin C) + +cmake_minimum_required(VERSION 2.6) +set(CMAKE_BACKWARDS_COMPATIBILITY 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +IF ( NOT CMAKE_INSTALL_LIBDIR ) + set(CMAKE_INSTALL_LIBDIR ~/.wireshark/plugins) +ENDIF ( NOT CMAKE_INSTALL_LIBDIR ) +MESSAGE (STATUS "Plugin will be installed in: ${CMAKE_INSTALL_LIBDIR}") + +INCLUDE(UseMakeDissectorReg) + +set(GLIB2_MIN_VERSION 2.4.0) + +find_package(GLIB2) +include_directories (${GLIB2_INCLUDE_DIRS}) + +find_package(Wireshark) +include_directories (${WIRESHARK_INCLUDE_DIRS}) + +set(LINK_MODE_LIB SHARED) +set(LINK_MODE_MODULE MODULE) + + +set(DISSECTOR_SRC + packet-btbredr.c + packet-btlmp.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} +) + +set(CLEAN_FILES + ${PLUGIN_FILES} +) + +if (WERROR) + set_source_files_properties( + ${CLEAN_FILES} + PROPERTIES + COMPILE_FLAGS -Werror + ) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +register_dissector_files(plugin.c + plugin + ${DISSECTOR_SRC} +) + +add_library(btbredr ${LINK_MODE_MODULE} + ${PLUGIN_FILES} +) +set_target_properties(btbredr PROPERTIES PREFIX "") +set_target_properties(btbredr PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}") + +target_link_libraries(btbredr wireshark) + +install(TARGETS btbredr + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/ NAMELINK_SKIP +) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/COPYING new file mode 100644 index 0000000..aa0aea5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/README b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/README new file mode 100644 index 0000000..d08629c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/README @@ -0,0 +1,16 @@ +BTBB Basic and Enhanced Data Rate Wireshark plugin + +This is the Bluetooth baseband plugin for Wireshark, it also includes an LMP +level dissector. + +To build this on Debian/Ubuntu/BackTrack linux distributions: + sudo apt-get install wireshark-dev wireshark + cd libbtbb/wireshark/plugins/btbredr/ + mkdir build + cd build + cmake .. + make + make install + +This will install to the .wireshark/ in your home directory. To override this +set the DESTDIR environment variable when running cmake. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/btbredr_test.pcap b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/btbredr_test.pcap new file mode 100644 index 0000000000000000000000000000000000000000..bb5cd8e5e3278e7833632e80cee8aefc8505a3b5 GIT binary patch literal 4793 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 literal 0 HcmV?d00001 diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING new file mode 100644 index 0000000..53b6b71 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING-CMAKE-SCRIPTS b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..280ed6c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,27 @@ +Copyright notice for the files copied from +http://www.opensync.org/browser/branches/3rd-party-cmake-modules/modules + +$Id: COPYING-CMAKE-SCRIPTS 34248 2010-09-25 15:38:12Z jmayer $ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindGLIB2.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindGLIB2.cmake new file mode 100644 index 0000000..ae7badd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindGLIB2.cmake @@ -0,0 +1,238 @@ +# +# $Id: FindGLIB2.cmake 34248 2010-09-25 15:38:12Z jmayer $ +# +# - Try to find GLib2 +# Once done this will define +# +# GLIB2_FOUND - system has GLib2 +# GLIB2_INCLUDE_DIRS - the GLib2 include directory +# GLIB2_LIBRARIES - Link these to use GLib2 +# +# HAVE_GLIB_GREGEX_H glib has gregex.h header and +# supports g_regex_match_simple +# +# Copyright (c) 2006 Andreas Schneider +# Copyright (c) 2006 Philippe Bernery +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Alban Browaeys +# Copyright (c) 2008 Michael Bell +# Copyright (c) 2008-2009 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +IF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + # in cache already + SET(GLIB2_FOUND TRUE) +ELSE (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + + INCLUDE(FindPkgConfig) + + ## Glib + IF ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) + ELSE ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) + ENDIF ( GLIB2_FIND_REQUIRED ) + + IF ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0>=${GLIB2_MIN_VERSION} ) + ELSE ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0 ) + ENDIF ( GLIB2_MIN_VERSION ) + IF ( PKG_CONFIG_FOUND ) + IF ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( GLIB2_FOUND ) + ENDIF ( PKG_CONFIG_FOUND ) + + # Look for glib2 include dir and libraries w/o pkgconfig + IF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( + _glibconfig_include_DIR + NAMES + glibconfig.h + PATHS + /opt/gnome/lib64 + /opt/gnome/lib + /opt/lib/ + /opt/local/lib + /sw/lib/ + /usr/lib64 + /usr/lib + /usr/local/include + ${CMAKE_LIBRARY_PATH} + PATH_SUFFIXES + glib-2.0/include + ) + + FIND_PATH( + _glib2_include_DIR + NAMES + glib.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + PATH_SUFFIXES + glib-2.0 + ) + + #MESSAGE(STATUS "Glib headers: ${_glib2_include_DIR}") + + FIND_LIBRARY( + _glib2_link_DIR + NAMES + glib-2.0 + glib + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + IF ( _glib2_include_DIR AND _glib2_link_DIR ) + SET ( _glib2_FOUND TRUE ) + ENDIF ( _glib2_include_DIR AND _glib2_link_DIR ) + + + IF ( _glib2_FOUND ) + SET ( GLIB2_INCLUDE_DIRS ${_glib2_include_DIR} ${_glibconfig_include_DIR} ) + SET ( GLIB2_LIBRARIES ${_glib2_link_DIR} ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( _glib2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( _glib2_FOUND ) + + # Handle dependencies + # libintl + IF ( NOT LIBINTL_FOUND ) + FIND_PATH(LIBINTL_INCLUDE_DIR + NAMES + libintl.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + ) + + FIND_LIBRARY(LIBINTL_LIBRARY + NAMES + intl + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/local/lib + /usr/lib + ) + + IF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + SET (LIBINTL_FOUND TRUE) + ENDIF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + ENDIF ( NOT LIBINTL_FOUND ) + + # libiconv + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR + NAMES + iconv.h + PATHS + /opt/gnome/include + /opt/local/include + /opt/local/include + /sw/include + /sw/include + /usr/local/include + /usr/include + PATH_SUFFIXES + glib-2.0 + ) + + FIND_LIBRARY(LIBICONV_LIBRARY + NAMES + iconv + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + + IF (LIBINTL_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBINTL_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBINTL_INCLUDE_DIR}) + ENDIF (LIBINTL_FOUND) + + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) + + ENDIF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + ## + + IF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + SET (GLIB2_FOUND TRUE) + ENDIF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + + IF (GLIB2_FOUND) + IF (NOT GLIB2_FIND_QUIETLY) + MESSAGE (STATUS "Found GLib2: ${GLIB2_LIBRARIES} ${GLIB2_INCLUDE_DIRS}") + ENDIF (NOT GLIB2_FIND_QUIETLY) + ELSE (GLIB2_FOUND) + IF (GLIB2_FIND_REQUIRED) + MESSAGE (SEND_ERROR "Could not find GLib2") + ENDIF (GLIB2_FIND_REQUIRED) + ENDIF (GLIB2_FOUND) + + # show the GLIB2_INCLUDE_DIRS and GLIB2_LIBRARIES variables only in the advanced view + MARK_AS_ADVANCED(GLIB2_INCLUDE_DIRS GLIB2_LIBRARIES) + MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARY) + MARK_AS_ADVANCED(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARY) + +ENDIF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS) + +IF ( WIN32 ) + # include libiconv for win32 + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h PATH_SUFFIXES glib-2.0) + + FIND_LIBRARY(LIBICONV_LIBRARY NAMES iconv) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) +ENDIF ( WIN32 ) + +IF ( GLIB2_FOUND ) + # Check if system has a newer version of glib + # which supports g_regex_match_simple + INCLUDE( CheckIncludeFiles ) + SET( CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS} ) + CHECK_INCLUDE_FILES ( glib/gregex.h HAVE_GLIB_GREGEX_H ) + CHECK_INCLUDE_FILES ( glib/gchecksum.h HAVE_GLIB_GCHECKSUM_H ) + # Reset CMAKE_REQUIRED_INCLUDES + SET( CMAKE_REQUIRED_INCLUDES "" ) +ENDIF( GLIB2_FOUND ) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindWireshark.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindWireshark.cmake new file mode 100644 index 0000000..16fabed --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/FindWireshark.cmake @@ -0,0 +1,28 @@ +# +# Try to find the wireshark library and its includes +# +# This snippet sets the following variables: +# WIRESHARK_FOUND True if wireshark library got found +# WIRESHARK_INCLUDE_DIRS Location of the wireshark headers +# WIRESHARK_LIBRARIES List of libraries to use wireshark +# +# Copyright (c) 2011 Reinhold Kainhofer +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# wireshark does not install its library with pkg-config information, +# so we need to manually find the libraries and headers + +FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/packet.h PATH_SUFFIXES wireshark ) +FIND_LIBRARY( WIRESHARK_LIBRARIES wireshark ) + +# Report results +IF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + SET( WIRESHARK_FOUND 1 ) +ELSE ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + MESSAGE( SEND_ERROR "Could NOT find the wireshark library and headers" ) +ENDIF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/UseMakeDissectorReg.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/UseMakeDissectorReg.cmake new file mode 100644 index 0000000..e7e1a73 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/cmake/UseMakeDissectorReg.cmake @@ -0,0 +1,33 @@ +# +# $Id: UseMakeDissectorReg.cmake 33616 2010-07-22 12:18:36Z stig $ +# +MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype ) + # FIXME: Only the Python stuff has been implemented + # Make this into a MACRO, to avoid duplication with plugins/.../ + #register.c: $(plugin_src) $(ALL_DISSECTORS_SRC) $(top_srcdir)/tools/make-dissector-reg \ + # $(top_srcdir)/tools/make-dissector-reg.py + # @if test -n "$(PYTHON)"; then \ + # echo Making register.c with python ; \ + # $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + # dissectors $(ALL_DISSECTORS_SRC) ; \ + # else \ + # echo Making register.c with shell script ; \ + # $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + # dissectors $(plugin_src) $(ALL_DISSECTORS_SRC) ; \ + # fi + set( _sources ${ARGN} ) + ADD_CUSTOM_COMMAND( + OUTPUT + ${_outputfile} + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ${CMAKE_CURRENT_SOURCE_DIR} + ${_registertype} + ${_sources} + DEPENDS + ${_sources} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ) +ENDMACRO(REGISTER_DISSECTOR_FILES) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/moduleinfo.h b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/moduleinfo.h new file mode 100644 index 0000000..fcf5c22 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/moduleinfo.h @@ -0,0 +1,17 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "btbredr" + + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "0.0.1" + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btbredr.c b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btbredr.c new file mode 100644 index 0000000..2954ccd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btbredr.c @@ -0,0 +1,673 @@ +/* packet-btbredr.c + * Routines for Bluetooth baseband dissection + * Copyright 2014, Dominic Spill + * Copyright 2009, Michael Ossmann + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#include +#endif + +#include +#include + +#include + +/* function prototypes */ +void proto_reg_handoff_btbredr(void); + +/* initialize the protocol and registered fields */ +static int proto_btbredr = -1; +static int hf_btbredr_meta = -1; +static int hf_btbredr_channel = -1; +static int hf_btbredr_signal = -1; +static int hf_btbredr_noise = -1; +static int hf_btbredr_ac_offenses = -1; +static int hf_btbredr_mod = -1; +static int hf_btbredr_transport = -1; +static int hf_btbredr_corrected_header = -1; +static int hf_btbredr_corrected_payload = -1; +static int hf_btbredr_lap = -1; +static int hf_btbredr_ref_lap = -1; +static int hf_btbredr_ref_uap = -1; +static int hf_btbredr_pkthdr = -1; +static int hf_btbredr_ltaddr = -1; +static int hf_btbredr_type = -1; +static int hf_btbredr_flags = -1; +static int hf_btbredr_flow = -1; +static int hf_btbredr_arqn = -1; +static int hf_btbredr_seqn = -1; +static int hf_btbredr_hec = -1; +static int hf_btbredr_payload = -1; +static int hf_btbredr_pldhdr = -1; +static int hf_btbredr_llid = -1; +static int hf_btbredr_pldflow = -1; +static int hf_btbredr_length = -1; +static int hf_btbredr_pldbody = -1; +static int hf_btbredr_crc = -1; +static int hf_btbredr_fhs_parity = -1; +static int hf_btbredr_fhs_lap = -1; +static int hf_btbredr_fhs_eir = -1; +static int hf_btbredr_fhs_sr = -1; +static int hf_btbredr_fhs_uap = -1; +static int hf_btbredr_fhs_nap = -1; +static int hf_btbredr_fhs_class = -1; +static int hf_btbredr_fhs_ltaddr = -1; +static int hf_btbredr_fhs_clk = -1; +static int hf_btbredr_fhs_psmode = -1; + +/* field values */ +static const true_false_string direction = { + "Slave to Master", + "Master to Slave" +}; + +static const true_false_string clock_bits = { + "27", + "6" +}; + +static const true_false_string valid_flags = { + "Invalid", + "Valid" +}; + +static const value_string modulation[] = { + { 0x0, "Basic Rate (GFSK)" }, + { 0x1, "Enhanced Data Rate (PI/2-DQPSK)" }, + { 0x2, "Enhanced Data Rate (8DPSK)" } +}; + +static const value_string transports[] = { + { 0x0, "unknown" }, + { 0x1, "SCO" }, + { 0x2, "eSCO" }, + { 0x3, "ACL" }, + { 0x4, "CSB" } +}; + +static const value_string packet_types[] = { + /* generic names for unknown logical transport */ + { 0x0, "NULL" }, + { 0x1, "POLL" }, + { 0x2, "FHS" }, + { 0x3, "DM1" }, + { 0x4, "DH1/2-DH1" }, + { 0x5, "HV1" }, + { 0x6, "HV2/2-EV3" }, + { 0x7, "HV3/EV3/3-EV3" }, + { 0x8, "DV/3-DH1" }, + { 0x9, "AUX1" }, + { 0xa, "DM3/2-DH3" }, + { 0xb, "DH3/3-DH3" }, + { 0xc, "EV4/2-EV5" }, + { 0xd, "EV5/3-EV5" }, + { 0xe, "DM5/2-DH5" }, + { 0xf, "DH5/3-DH5" }, + { 0, NULL } +}; + +static const value_string sr_modes[] = { + { 0x0, "R0" }, + { 0x1, "R1" }, + { 0x2, "R2" }, + { 0x3, "Reserved" }, + { 0, NULL } +}; + +static const range_string ps_modes[] = { + { 0x0, 0x0, "Mandatory scan mode" }, + { 0x1, 0x7, "Reserved" }, + { 0, 0, NULL } +}; + +static const value_string llid_codes[] = { + { 0x0, "undefined" }, + { 0x1, "Continuation fragment of an L2CAP message (ACL-U)" }, + { 0x2, "Start of an L2CAP message or no fragmentation (ACL-U)" }, + { 0x3, "LMP message (ACL-C)" }, + { 0, NULL } +}; + +/* initialize the subtree pointers */ +static gint ett_btbredr = -1; +static gint ett_btbredr_meta = -1; +static gint ett_btbredr_pkthdr = -1; +static gint ett_btbredr_flags = -1; +static gint ett_btbredr_payload = -1; +static gint ett_btbredr_pldhdr = -1; + +/* subdissectors */ +static dissector_handle_t btlmp_handle = NULL; +static dissector_handle_t btl2cap_handle = NULL; + +/* packet header flags */ +static const int *flag_fields[] = { + &hf_btbredr_flow, + &hf_btbredr_arqn, + &hf_btbredr_seqn, + NULL +}; + +/* one byte payload header */ +int +dissect_payload_header1(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_item *hdr_item; + proto_tree *hdr_tree; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + hdr_item = proto_tree_add_item(tree, hf_btbredr_pldhdr, tvb, offset, 1, ENC_NA); + hdr_tree = proto_item_add_subtree(hdr_item, ett_btbredr_pldhdr); + + proto_tree_add_item(hdr_tree, hf_btbredr_llid, tvb, offset, 1, ENC_NA); + proto_tree_add_item(hdr_tree, hf_btbredr_pldflow, tvb, offset, 1, ENC_NA); + proto_tree_add_item(hdr_tree, hf_btbredr_length, tvb, offset, 1, ENC_NA); + + /* payload length */ + return tvb_get_guint8(tvb, offset) >> 3; +} + +void +dissect_fhs(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) +{ + proto_item *fhs_item, *psmode_item; + proto_tree *fhs_tree; + const gchar *description; + guint8 psmode; + + if(tvb_length_remaining(tvb, offset) != 20) { + col_add_str(pinfo->cinfo, COL_INFO, "Encrypted or malformed payload data"); + return; + } + + fhs_item = proto_tree_add_item(tree, hf_btbredr_payload, tvb, offset, -1, ENC_NA); + fhs_tree = proto_item_add_subtree(fhs_item, ett_btbredr_payload); + + /* Use proto_tree_add_bits_item() to get around 32bit limit on bitmasks */ + proto_tree_add_bits_item(fhs_tree, hf_btbredr_fhs_parity, tvb, offset*8, 34, ENC_LITTLE_ENDIAN); + /* proto_tree_add_item(fhs_tree, hf_btbredr_fhs_parity, tvb, offset, 5, ENC_LITTLE_ENDIAN); */ + offset += 4; + + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_lap, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 3; + + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_eir, tvb, offset, 1, ENC_NA); + /* skipping 1 undefined bit */ + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_sr, tvb, offset, 1, ENC_NA); + /* skipping 2 reserved bits */ + offset += 1; + + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_uap, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_nap, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_class, tvb, offset, 3, ENC_LITTLE_ENDIAN); + offset += 3; + + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_ltaddr, tvb, offset, 1, ENC_NA); + proto_tree_add_item(fhs_tree, hf_btbredr_fhs_clk, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 3; + + psmode = tvb_get_guint8(tvb, offset); + description = try_rval_to_str(psmode, ps_modes); + psmode_item = proto_tree_add_item(fhs_tree, hf_btbredr_fhs_psmode, tvb, offset, 1, ENC_NA); + if (description) + proto_item_append_text(psmode_item, " (%s)", description); + offset += 1; + + proto_tree_add_item(fhs_tree, hf_btbredr_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; +} + +void +dissect_dm1(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) +{ + int len; /* payload length indicated by payload header */ + int llid; /* logical link id */ + int l2len; /* length indicated by l2cap header */ + proto_item *dm1_item; + proto_tree *dm1_tree; + tvbuff_t *pld_tvb; + + /* + * FIXME + * I'm probably doing a terrible, terrible thing here, but it gets my + * initial test cases working. + */ + guint16 fake_acl_data; + + if(tvb_length_remaining(tvb, offset) < 3) { + col_add_str(pinfo->cinfo, COL_INFO, "Encrypted or malformed payload data"); + return; + } + + dm1_item = proto_tree_add_item(tree, hf_btbredr_payload, tvb, offset, -1, ENC_NA); + dm1_tree = proto_item_add_subtree(dm1_item, ett_btbredr_payload); + + len = dissect_payload_header1(dm1_tree, tvb, offset); + llid = tvb_get_guint8(tvb, offset) & 0x3; + offset += 1; + + if(tvb_length_remaining(tvb, offset) < len + 2) { + col_add_str(pinfo->cinfo, COL_INFO, "Encrypted or malformed payload data"); + return; + } + + if (llid == 3 && btlmp_handle) { + /* LMP */ + pld_tvb = tvb_new_subset(tvb, offset, len, len); + call_dissector(btlmp_handle, pld_tvb, pinfo, dm1_tree); + } else if (llid == 2 && btl2cap_handle) { + /* unfragmented L2CAP or start of fragment */ + l2len = tvb_get_letohs(tvb, offset); + if (l2len + 4 == len) { + /* unfragmented */ + pinfo->private_data = &fake_acl_data; + pld_tvb = tvb_new_subset(tvb, offset, len, len); + call_dissector(btl2cap_handle, pld_tvb, pinfo, dm1_tree); + } else { + /* start of fragment */ + proto_tree_add_item(dm1_tree, hf_btbredr_pldbody, tvb, offset, len, ENC_NA); + } + } else { + proto_tree_add_item(dm1_tree, hf_btbredr_pldbody, tvb, offset, len, ENC_NA); + } + offset += len; + + proto_tree_add_item(dm1_tree, hf_btbredr_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; +} + +/* dissect a packet */ +static int +dissect_btbredr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *btbredr_item, *meta_item, *pkthdr_item; + proto_tree *btbredr_tree, *meta_tree, *pkthdr_tree; + int offset; + /* Avoid error: 'type' may be used uninitialized in this function */ + guint8 type = 0xff; + const gchar *info; + + /* sanity check: length */ + if (tvb_length(tvb) > 0 && tvb_length(tvb) < 9) + /* bad length: look for a different dissector */ + return 0; + + /* maybe should verify HEC */ + + /* make entries in protocol column and info column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bluetooth"); + + if (tvb_length(tvb) == 0) { + info = "ID"; + } else { + type = (tvb_get_guint8(tvb, 16) >> 3) & 0x0f; + info = val_to_str(type, packet_types, "Unknown type: 0x%x"); + } + + col_clear(pinfo->cinfo, COL_INFO); + col_add_str(pinfo->cinfo, COL_INFO, info); + + /* see if we are being asked for details */ + if (tree) { + + /* create display subtree for the protocol */ + offset = 0; + btbredr_item = proto_tree_add_item(tree, proto_btbredr, tvb, offset, -1, ENC_NA); + btbredr_tree = proto_item_add_subtree(btbredr_item, ett_btbredr); + + /* ID packets have no header, no payload */ + if (tvb_length(tvb) == 0) + return 1; + + /* meta data */ + meta_item = proto_tree_add_item(btbredr_tree, hf_btbredr_meta, tvb, offset, 3, ENC_NA); + meta_tree = proto_item_add_subtree(meta_item, ett_btbredr_meta); + + proto_tree_add_item(meta_tree, hf_btbredr_channel, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(meta_tree, hf_btbredr_signal, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(meta_tree, hf_btbredr_noise, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(meta_tree, hf_btbredr_ac_offenses, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(meta_tree, hf_btbredr_mod, tvb, offset, 1, ENC_NA); + proto_tree_add_item(meta_tree, hf_btbredr_transport, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(meta_tree, hf_btbredr_corrected_header, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(meta_tree, hf_btbredr_corrected_payload, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(meta_tree, hf_btbredr_lap, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(meta_tree, hf_btbredr_ref_lap, tvb, offset, 3, ENC_LITTLE_ENDIAN); + offset += 3; + proto_tree_add_item(meta_tree, hf_btbredr_ref_uap, tvb, offset, 1, ENC_NA); + offset += 1; + + + /* packet header */ + pkthdr_item = proto_tree_add_item(btbredr_tree, hf_btbredr_pkthdr, tvb, offset, 3, ENC_NA); + pkthdr_tree = proto_item_add_subtree(pkthdr_item, ett_btbredr_pkthdr); + + proto_tree_add_item(pkthdr_tree, hf_btbredr_ltaddr, tvb, offset, 1, ENC_NA); + proto_tree_add_item(pkthdr_tree, hf_btbredr_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_bitmask(pkthdr_tree, tvb, offset, hf_btbredr_flags, + ett_btbredr_flags, flag_fields, ENC_NA); + offset += 1; + proto_tree_add_item(pkthdr_tree, hf_btbredr_hec, tvb, offset, 1, ENC_NA); + offset += 2; + + /* payload */ + switch (type) { + case 0x0: /* NULL */ + case 0x1: /* POLL */ + break; + case 0x2: /* FHS */ + dissect_fhs(btbredr_tree, tvb, pinfo, offset); + break; + case 0x3: /* DM1 */ + dissect_dm1(btbredr_tree, tvb, pinfo, offset); + break; + case 0x4: /* DH1/2-DH1 */ + dissect_dm1(btbredr_tree, tvb, pinfo, offset); + break; + case 0x5: /* HV1 */ + case 0x6: /* HV2/2-EV3 */ + case 0x7: /* HV3/EV3/3-EV3 */ + case 0x8: /* DV/3-DH1 */ + case 0x9: /* AUX1 */ + case 0xa: /* DM3/2-DH3 */ + case 0xb: /* DH3/3-DH3 */ + case 0xc: /* EV4/2-EV5 */ + case 0xd: /* EV5/3-EV5 */ + case 0xe: /* DM5/2-DH5 */ + case 0xf: /* DH5/3-DH5 */ + proto_tree_add_item(btbredr_tree, hf_btbredr_payload, tvb, offset, -1, ENC_NA); + break; + default: + break; + } + } + + /* Return the amount of data this dissector was able to dissect */ + return tvb_length(tvb); +} + +/* register the protocol with Wireshark */ +void +proto_register_btbredr(void) +{ + /* list of fields */ + static hf_register_info hf[] = { + { &hf_btbredr_meta, + { "Meta Data", "btbredr.meta", + FT_NONE, BASE_NONE, NULL, 0x0, + "Meta Data About the Packet", HFILL } + }, + { &hf_btbredr_channel, + { "Channel", "btbredr.channel", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Channel (0-78)", HFILL } + }, + { &hf_btbredr_signal, + { "Signal", "btbredr.signal", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Signal Power", HFILL } + }, + { &hf_btbredr_noise, + { "Noise", "btbredr.noise", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Noise Power", HFILL } + }, + { &hf_btbredr_ac_offenses, + { "AC Offenses", "btbredr.ac_offenses", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Access Code Offenses", HFILL } + }, + { &hf_btbredr_mod, + { "Transport Rate", "btbredr.mod", + FT_UINT8, BASE_HEX, VALS(&modulation), 0x02, + "Transport Data Rate", HFILL } + }, + { &hf_btbredr_transport, + { "Transport", "btbredr.transport", + FT_UINT8, BASE_HEX, VALS(&transports), 0x70, + "Logical Transport", HFILL } + }, + { &hf_btbredr_corrected_header, + { "Corrected Header", "btbredr.corrected_header", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Corrected Header Bits", HFILL } + }, + { &hf_btbredr_corrected_payload, + { "Corrected Payload", "btbredr.corrected_payload", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Corrected Payload Bits", HFILL } + }, + { &hf_btbredr_lap, + { "LAP", "btbredr.lap", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Lower Address Part", HFILL } + }, + { &hf_btbredr_ref_lap, + { "Ref. LAP", "btbredr.ref_lap", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Reference LAP", HFILL } + }, + { &hf_btbredr_ref_uap, + { "Ref. UAP", "btbredr.ref_uap", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Reference UAP", HFILL } + }, + { &hf_btbredr_pkthdr, + { "Packet Header", "btbredr.pkthdr", + FT_NONE, BASE_NONE, NULL, 0x0, + "Bluetooth Baseband Packet Header", HFILL } + }, + { &hf_btbredr_ltaddr, + { "LT_ADDR", "btbredr.lt_addr", + FT_UINT8, BASE_HEX, NULL, 0x07, + "Logical Transport Address", HFILL } + }, + { &hf_btbredr_type, + { "TYPE", "btbredr.type", + FT_UINT8, BASE_HEX, VALS(packet_types), 0x78, + "Packet Type", HFILL } + }, + { &hf_btbredr_flags, + { "Flags", "btbredr.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Packet Header Flags", HFILL } + }, + { &hf_btbredr_flow, + { "FLOW", "btbredr.flow", + FT_BOOLEAN, 8, NULL, 0x01, + "Flow control indication", HFILL } + }, + { &hf_btbredr_arqn, + { "ARQN", "btbredr.arqn", + FT_BOOLEAN, 8, NULL, 0x02, + "Acknowledgment indication", HFILL } + }, + { &hf_btbredr_seqn, + { "SEQN", "btbredr.seqn", + FT_BOOLEAN, 8, NULL, 0x04, + "Sequence number", HFILL } + }, + { &hf_btbredr_hec, + { "HEC", "btbredr.lt_addr", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Header Error Check", HFILL } + }, + { &hf_btbredr_payload, + { "Payload", "btbredr.payload", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbredr_llid, + { "LLID", "btbredr.llid", + FT_UINT8, BASE_HEX, VALS(llid_codes), 0x03, + "Logical Link ID", HFILL } + }, + { &hf_btbredr_pldflow, + { "Flow", "btbredr.flow", + FT_BOOLEAN, 8, NULL, 0x04, + "Payload Flow indication", HFILL } + }, + { &hf_btbredr_length, + { "Length", "btbredr.length", + FT_UINT8, BASE_DEC, NULL, 0xf8, + "Payload Length", HFILL } + }, + { &hf_btbredr_pldhdr, + { "Payload Header", "btbredr.pldhdr", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbredr_pldbody, + { "Payload Body", "btbredr.pldbody", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbredr_crc, + { "CRC", "btbredr.crc", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Payload CRC", HFILL } + }, + { &hf_btbredr_fhs_parity, + { "Parity", "btbredr.parity", + /* FIXME this doesn't work because bitmasks can only be 32 bits */ + FT_UINT64, BASE_HEX, NULL, /*0x00000003ffffffffULL,*/ 0x0, + "LAP parity", HFILL } + }, + { &hf_btbredr_fhs_lap, + { "LAP", "btbredr.lap", + FT_UINT24, BASE_HEX, NULL, 0x03fffffc, + "Lower Address Part", HFILL } + }, + { &hf_btbredr_fhs_eir, + { "EIR", "btbredr.eir", + FT_BOOLEAN, 8, NULL, 0x04, + "Extended Inquiry Response packet may follow", HFILL } + }, + { &hf_btbredr_fhs_sr, + { "SR", "btbredr.sr", + FT_UINT8, BASE_HEX, VALS(sr_modes), 0x30, + "Scan Repetition", HFILL } + }, + { &hf_btbredr_fhs_uap, + { "UAP", "btbredr.uap", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Upper Address Part", HFILL } + }, + { &hf_btbredr_fhs_nap, + { "NAP", "btbredr.nap", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Non-Significant Address Part", HFILL } + }, + { &hf_btbredr_fhs_class, /* FIXME break out further */ + { "Class of Device", "btbredr.class", + FT_UINT24, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btbredr_fhs_ltaddr, + { "LT_ADDR", "btbredr.lt_addr", + FT_UINT8, BASE_HEX, NULL, 0x07, + "Logical Transport Address", HFILL } + }, + { &hf_btbredr_fhs_clk, + { "CLK", "btbredr.clk", + FT_UINT32, BASE_HEX, NULL, 0x1ffffff8, + "Clock bits 2 through 27", HFILL } + }, + { &hf_btbredr_fhs_psmode, + { "Page Scan Mode", "btbredr.psmode", + FT_UINT8, BASE_HEX, NULL, 0xe0, + NULL, HFILL } + }, + }; + + /* protocol subtree arrays */ + static gint *ett[] = { + &ett_btbredr, + &ett_btbredr_meta, + &ett_btbredr_pkthdr, + &ett_btbredr_flags, + &ett_btbredr_payload, + &ett_btbredr_pldhdr, + }; + + /* register the protocol name and description */ + proto_btbredr = proto_register_protocol( + "Bluetooth BR/EDR Baseband", /* full name */ + "BT BR/EDR Baseband", /* short name */ + "btbredr" /* abbreviation (e.g. for filters) */ + ); + + /* register the header fields and subtrees used */ + proto_register_field_array(proto_btbredr, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +/* Remove this once recent Wireshark/TCPdump releases are more common */ +#ifndef WTAP_ENCAP_BLUETOOTH_BREDR_BB +#define WTAP_ENCAP_BLUETOOTH_BREDR_BB 161 +#endif + +void +proto_reg_handoff_btbredr(void) +{ + dissector_handle_t btbredr_handle; + btbredr_handle = new_create_dissector_handle(dissect_btbredr, + proto_btbredr); + dissector_add_uint("wtap_encap", + WTAP_ENCAP_BLUETOOTH_BREDR_BB, + btbredr_handle); + + btlmp_handle = find_dissector("btlmp"); + btl2cap_handle = find_dissector("btl2cap"); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btlmp.c b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btlmp.c new file mode 100644 index 0000000..1a67a2c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/packet-btlmp.c @@ -0,0 +1,2887 @@ +/* packet-btlmp.c + * Routines for Bluetooth LMP dissection + * Copyright 2009, Michael Ossmann + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#include +#endif + +#include /* needed for epan/gcc-4.x */ +#include +#include + +/* LMP opcodes */ +#define LMP_NAME_REQ 1 +#define LMP_NAME_RES 2 +#define LMP_ACCEPTED 3 +#define LMP_NOT_ACCEPTED 4 +#define LMP_CLKOFFSET_REQ 5 +#define LMP_CLKOFFSET_RES 6 +#define LMP_DETACH 7 +#define LMP_IN_RAND 8 +#define LMP_COMB_KEY 9 +#define LMP_UNIT_KEY 10 +#define LMP_AU_RAND 11 +#define LMP_SRES 12 +#define LMP_TEMP_RAND 13 +#define LMP_TEMP_KEY 14 +#define LMP_ENCRYPTION_MODE_REQ 15 +#define LMP_ENCRYPTION_KEY_SIZE_REQ 16 +#define LMP_START_ENCRYPTION_REQ 17 +#define LMP_STOP_ENCRYPTION_REQ 18 +#define LMP_SWITCH_REQ 19 +#define LMP_HOLD 20 +#define LMP_HOLD_REQ 21 +#define LMP_SNIFF_REQ 23 +#define LMP_UNSNIFF_REQ 24 +#define LMP_PARK_REQ 25 +#define LMP_SET_BROADCAST_SCAN_WINDOW 27 +#define LMP_MODIFY_BEACON 28 +#define LMP_UNPARK_BD_ADDR_REQ 29 +#define LMP_UNPARK_PM_ADDR_REQ 30 +#define LMP_INCR_POWER_REQ 31 +#define LMP_DECR_POWER_REQ 32 +#define LMP_MAX_POWER 33 +#define LMP_MIN_POWER 34 +#define LMP_AUTO_RATE 35 +#define LMP_PREFERRED_RATE 36 +#define LMP_VERSION_REQ 37 +#define LMP_VERSION_RES 38 +#define LMP_FEATURES_REQ 39 +#define LMP_FEATURES_RES 40 +#define LMP_QUALITY_OF_SERVICE 41 +#define LMP_QUALITY_OF_SERVICE_REQ 42 +#define LMP_SCO_LINK_REQ 43 +#define LMP_REMOVE_SCO_LINK_REQ 44 +#define LMP_MAX_SLOT 45 +#define LMP_MAX_SLOT_REQ 46 +#define LMP_TIMING_ACCURACY_REQ 47 +#define LMP_TIMING_ACCURACY_RES 48 +#define LMP_SETUP_COMPLETE 49 +#define LMP_USE_SEMI_PERMANENT_KEY 50 +#define LMP_HOST_CONNECTION_REQ 51 +#define LMP_SLOT_OFFSET 52 +#define LMP_PAGE_MODE_REQ 53 +#define LMP_PAGE_SCAN_MODE_REQ 54 +#define LMP_SUPERVISION_TIMEOUT 55 +#define LMP_TEST_ACTIVATE 56 +#define LMP_TEST_CONTROL 57 +#define LMP_ENCRYPTION_KEY_SIZE_MASK_REQ 58 +#define LMP_ENCRYPTION_KEY_SIZE_MASK_RES 59 +#define LMP_SET_AFH 60 +#define LMP_ENCAPSULATED_HEADER 61 +#define LMP_ENCAPSULATED_PAYLOAD 62 +#define LMP_SIMPLE_PAIRING_CONFIRM 63 +#define LMP_SIMPLE_PAIRING_NUMBER 64 +#define LMP_DHKEY_CHECK 65 +#define LMP_ESCAPE_1 124 +#define LMP_ESCAPE_2 125 +#define LMP_ESCAPE_3 126 +#define LMP_ESCAPE_4 127 + +/* LMP extended opcodes */ +#define LMP_ACCEPTED_EXT 1 +#define LMP_NOT_ACCEPTED_EXT 2 +#define LMP_FEATURES_REQ_EXT 3 +#define LMP_FEATURES_RES_EXT 4 +#define LMP_PACKET_TYPE_TABLE_REQ 11 +#define LMP_ESCO_LINK_REQ 12 +#define LMP_REMOVE_ESCO_LINK_REQ 13 +#define LMP_CHANNEL_CLASSIFICATION_REQ 16 +#define LMP_CHANNEL_CLASSIFICATION 17 +#define LMP_SNIFF_SUBRATING_REQ 21 +#define LMP_SNIFF_SUBRATING_RES 22 +#define LMP_PAUSE_ENCRYPTION_REQ 23 +#define LMP_RESUME_ENCRYPTION_REQ 24 +#define LMP_IO_CAPABILITY_REQ 25 +#define LMP_IO_CAPABILITY_RES 26 +#define LMP_NUMERIC_COMPARISON_FAILED 27 +#define LMP_PASSKEY_FAILED 28 +#define LMP_OOB_FAILED 29 +#define LMP_KEYPRESS_NOTIFICATION 30 +#define LMP_POWER_CONTROL_REQ 31 +#define LMP_POWER_CONTROL_RES 32 + +/* initialize the protocol and registered fields */ +static int proto_btlmp = -1; +static int hf_lmp_accscheme = -1; +static int hf_lmp_afhchmap = -1; +static int hf_lmp_afhclass = -1; +static int hf_lmp_afhinst = -1; +static int hf_lmp_afhmaxintvl = -1; +static int hf_lmp_afhminintvl = -1; +static int hf_lmp_afhmode = -1; +static int hf_lmp_afhrptmode = -1; +static int hf_lmp_airmode = -1; +static int hf_lmp_araddr = -1; +static int hf_lmp_authreqs = -1; +static int hf_lmp_authres = -1; +static int hf_lmp_bdaddr = -1; +static int hf_lmp_bdaddr1 = -1; +static int hf_lmp_bdaddr2 = -1; +static int hf_lmp_bsw = -1; +static int hf_lmp_clkoffset = -1; +static int hf_lmp_commit = -1; +static int hf_lmp_confirm = -1; +static int hf_lmp_compid = -1; +static int hf_lmp_cryptmode = -1; +static int hf_lmp_daccess = -1; +static int hf_lmp_db = -1; +static int hf_lmp_dbsleep = -1; +static int hf_lmp_deltab = -1; +static int hf_lmp_desco = -1; +static int hf_lmp_drift = -1; +static int hf_lmp_dsco = -1; +static int hf_lmp_dsniff = -1; +static int hf_lmp_encdata = -1; +static int hf_lmp_enclen = -1; +static int hf_lmp_encmaj = -1; +static int hf_lmp_encmin = -1; +static int hf_lmp_eop = -1; +static int hf_lmp_eopinre = -1; +static int hf_lmp_escolenms = -1; +static int hf_lmp_escolensm = -1; +static int hf_lmp_escotypems = -1; +static int hf_lmp_escotypesm = -1; +static int hf_lmp_err = -1; +static int hf_lmp_escohdl = -1; +static int hf_lmp_escoltaddr = -1; +static int hf_lmp_features = -1; +static int hf_lmp_fpage = -1; +static int hf_lmp_htime = -1; +static int hf_lmp_hinst = -1; +static int hf_lmp_hopmode = -1; +static int hf_lmp_iocaps = -1; +static int hf_lmp_jitter = -1; +static int hf_lmp_key = -1; +static int hf_lmp_keysz = -1; +static int hf_lmp_ksmask = -1; +static int hf_lmp_ltaddr1 = -1; +static int hf_lmp_ltaddr2 = -1; +static int hf_lmp_ltaddr3 = -1; +static int hf_lmp_ltaddr4 = -1; +static int hf_lmp_ltaddr5 = -1; +static int hf_lmp_ltaddr6 = -1; +static int hf_lmp_ltaddr7 = -1; +static int hf_lmp_maccess = -1; +static int hf_lmp_maxslots = -1; +static int hf_lmp_maxsp = -1; +static int hf_lmp_maxss = -1; +static int hf_lmp_minsmt = -1; +static int hf_lmp_naccslots = -1; +static int hf_lmp_namefrag = -1; +static int hf_lmp_namelen = -1; +static int hf_lmp_nameoffset = -1; +static int hf_lmp_nb = -1; +static int hf_lmp_nbc = -1; +static int hf_lmp_nbsleep = -1; +static int hf_lmp_negstate = -1; +static int hf_lmp_nonce = -1; +static int hf_lmp_nottype = -1; +static int hf_lmp_npoll = -1; +static int hf_lmp_oobauthdata = -1; +static int hf_lmp_op = -1; +static int hf_lmp_opinre = -1; +static int hf_lmp_pagesch = -1; +static int hf_lmp_pcmode = -1; +static int hf_lmp_pkttype = -1; +static int hf_lmp_pkttypetbl = -1; +static int hf_lmp_pmaddr = -1; +static int hf_lmp_pmaddr1 = -1; +static int hf_lmp_pmaddr2 = -1; +static int hf_lmp_pmaddr3 = -1; +static int hf_lmp_pmaddr4 = -1; +static int hf_lmp_pmaddr5 = -1; +static int hf_lmp_pmaddr6 = -1; +static int hf_lmp_pmaddr7 = -1; +static int hf_lmp_pollintvl = -1; +static int hf_lmp_pollper = -1; +static int hf_lmp_pssettings = -1; +static int hf_lmp_pwradjreq = -1; +static int hf_lmp_pwradjres = -1; +static int hf_lmp_pwradj_8dpsk = -1; +static int hf_lmp_pwradj_dqpsk = -1; +static int hf_lmp_pwradj_gfsk = -1; +static int hf_lmp_rand = -1; +static int hf_lmp_rate = -1; +static int hf_lmp_rate_fec = -1; +static int hf_lmp_rate_size = -1; +static int hf_lmp_rate_type = -1; +static int hf_lmp_rate_edrsize = -1; +static int hf_lmp_rxfreq = -1; +static int hf_lmp_scohdl = -1; +static int hf_lmp_scopkt = -1; +static int hf_lmp_slotoffset = -1; +static int hf_lmp_sniffatt = -1; +static int hf_lmp_sniffsi = -1; +static int hf_lmp_sniffto = -1; +static int hf_lmp_subversnr = -1; +static int hf_lmp_suptimeout = -1; +static int hf_lmp_swinst = -1; +static int hf_lmp_taccess = -1; +static int hf_lmp_tb = -1; +static int hf_lmp_tesco = -1; +static int hf_lmp_testlen = -1; +static int hf_lmp_testscen = -1; +static int hf_lmp_tid = -1; +static int hf_lmp_timectrl = -1; +static int hf_lmp_time_change = -1; +static int hf_lmp_time_init = -1; +static int hf_lmp_time_accwin = -1; +static int hf_lmp_tsco = -1; +static int hf_lmp_tsniff = -1; +static int hf_lmp_txfreq = -1; +static int hf_lmp_versnr = -1; +static int hf_lmp_wesco = -1; + +/* timing control flags */ +static const int *timectrl_fields[] = { + &hf_lmp_time_change, + &hf_lmp_time_init, + &hf_lmp_time_accwin, + /* bits 3-7 reserved */ + NULL +}; + +static const true_false_string time_change = { + "timing change", + "no timing change" +}; + +static const true_false_string time_init = { + "use initialization 2", + "use initialization 1" +}; + +static const true_false_string time_accwin = { + "no access window", + "access window" +}; + +static const true_false_string fec = { + "do not use FEC", + "use FEC" +}; + +static const true_false_string tid = { + "transaction initiated by slave", + "transaction initiated by master" +}; + +/* short LMP opcodes */ +static const value_string opcode[] = { + { LMP_NAME_REQ, "LMP_name_req" }, + { LMP_NAME_RES, "LMP_name_res" }, + { LMP_ACCEPTED, "LMP_accepted" }, + { LMP_NOT_ACCEPTED, "LMP_not_accepted" }, + { LMP_CLKOFFSET_REQ, "LMP_clkoffset_req" }, + { LMP_CLKOFFSET_RES, "LMP_clkoffset_res" }, + { LMP_DETACH, "LMP_detach" }, + { LMP_IN_RAND, "LMP_in_rand" }, + { LMP_COMB_KEY, "LMP_comb_key" }, + { LMP_UNIT_KEY, "LMP_unit_key" }, + { LMP_AU_RAND, "LMP_au_rand" }, + { LMP_SRES, "LMP_sres" }, + { LMP_TEMP_RAND, "LMP_temp_rand" }, + { LMP_TEMP_KEY, "LMP_temp_key" }, + { LMP_ENCRYPTION_MODE_REQ, "LMP_encryption_mode_req" }, + { LMP_ENCRYPTION_KEY_SIZE_REQ, "LMP_encryption_key_size_req" }, + { LMP_START_ENCRYPTION_REQ, "LMP_start_encryption_req" }, + { LMP_STOP_ENCRYPTION_REQ, "LMP_stop_encryption_req" }, + { LMP_SWITCH_REQ, "LMP_switch_req" }, + { LMP_HOLD, "LMP_hold" }, + { LMP_HOLD_REQ, "LMP_hold_req" }, + { LMP_SNIFF_REQ, "LMP_sniff_req" }, + { LMP_UNSNIFF_REQ, "LMP_unsniff_req" }, + { LMP_PARK_REQ, "LMP_park_req" }, + { LMP_SET_BROADCAST_SCAN_WINDOW, "LMP_set_broadcast_scan_window" }, + { LMP_MODIFY_BEACON, "LMP_modify_beacon" }, + { LMP_UNPARK_BD_ADDR_REQ, "LMP_unpark_BD_ADDR_req" }, + { LMP_UNPARK_PM_ADDR_REQ, "LMP_unpark_PM_ADDR_req" }, + { LMP_INCR_POWER_REQ, "LMP_incr_power_req" }, + { LMP_DECR_POWER_REQ, "LMP_decr_power_req" }, + { LMP_MAX_POWER, "LMP_max_power" }, + { LMP_MIN_POWER, "LMP_min_power" }, + { LMP_AUTO_RATE, "LMP_auto_rate" }, + { LMP_PREFERRED_RATE, "LMP_preferred_rate" }, + { LMP_VERSION_REQ, "LMP_version_req" }, + { LMP_VERSION_RES, "LMP_version_res" }, + { LMP_FEATURES_REQ, "LMP_features_req" }, + { LMP_FEATURES_RES, "LMP_features_res" }, + { LMP_QUALITY_OF_SERVICE, "LMP_quality_of_service" }, + { LMP_QUALITY_OF_SERVICE_REQ, "LMP_quality_of_service_req" }, + { LMP_SCO_LINK_REQ, "LMP_SCO_link_req" }, + { LMP_REMOVE_SCO_LINK_REQ, "LMP_remove_SCO_link_req" }, + { LMP_MAX_SLOT, "LMP_max_slot" }, + { LMP_MAX_SLOT_REQ, "LMP_max_slot_req" }, + { LMP_TIMING_ACCURACY_REQ, "LMP_timing_accuracy_req" }, + { LMP_TIMING_ACCURACY_RES, "LMP_timing_accuracy_res" }, + { LMP_SETUP_COMPLETE, "LMP_setup_complete" }, + { LMP_USE_SEMI_PERMANENT_KEY, "LMP_use_semi_permanent_key" }, + { LMP_HOST_CONNECTION_REQ, "LMP_host_connection_req" }, + { LMP_SLOT_OFFSET, "LMP_slot_offset" }, + { LMP_PAGE_MODE_REQ, "LMP_page_mode_req" }, + { LMP_PAGE_SCAN_MODE_REQ, "LMP_page_scan_mode_req" }, + { LMP_SUPERVISION_TIMEOUT, "LMP_supervision_timeout" }, + { LMP_TEST_ACTIVATE, "LMP_test_activate" }, + { LMP_TEST_CONTROL, "LMP_test_control" }, + { LMP_ENCRYPTION_KEY_SIZE_MASK_REQ, "LMP_encryption_key_size_mask_req" }, + { LMP_ENCRYPTION_KEY_SIZE_MASK_RES, "LMP_encryption_key_size_mask_res" }, + { LMP_SET_AFH, "LMP_set_AFH" }, + { LMP_ENCAPSULATED_HEADER, "LMP_encapsulated_header" }, + { LMP_ENCAPSULATED_PAYLOAD, "LMP_encapsulated_payload" }, + { LMP_SIMPLE_PAIRING_CONFIRM, "LMP_Simple_Pairing_Confirm" }, + { LMP_SIMPLE_PAIRING_NUMBER, "LMP_Simple_Pairing_Number" }, + { LMP_DHKEY_CHECK, "LMP_DHkey_Check" }, + { LMP_ESCAPE_1, "Escape 1" }, + { LMP_ESCAPE_2, "Escape 2" }, + { LMP_ESCAPE_3, "Escape 3" }, + { LMP_ESCAPE_4, "Escape 4" }, + { 0, NULL } +}; + +/* extended LMP opcodes */ +static const value_string ext_opcode[] = { + { LMP_ACCEPTED_EXT, "LMP_accepted_ext" }, + { LMP_NOT_ACCEPTED_EXT, "LMP_not_accepted_ext" }, + { LMP_FEATURES_REQ_EXT, "LMP_features_req_ext" }, + { LMP_FEATURES_RES_EXT, "LMP_features_res_ext" }, + { LMP_PACKET_TYPE_TABLE_REQ, "LMP_packet_type_table_req" }, + { LMP_ESCO_LINK_REQ, "LMP_eSCO_link_req" }, + { LMP_REMOVE_ESCO_LINK_REQ, "LMP_remove_eSCO_link_req" }, + { LMP_CHANNEL_CLASSIFICATION_REQ, "LMP_channel_classification_req" }, + { LMP_CHANNEL_CLASSIFICATION, "LMP_channel_classification" }, + { LMP_SNIFF_SUBRATING_REQ, "LMP_sniff_subrating_req" }, + { LMP_SNIFF_SUBRATING_RES, "LMP_sniff_subrating_res" }, + { LMP_PAUSE_ENCRYPTION_REQ, "LMP_pause_encryption_req" }, + { LMP_RESUME_ENCRYPTION_REQ, "LMP_resume_encryption_req" }, + { LMP_IO_CAPABILITY_REQ, "LMP_IO_Capability_req" }, + { LMP_IO_CAPABILITY_RES, "LMP_IO_Capability_res" }, + { LMP_NUMERIC_COMPARISON_FAILED, "LMP_numeric_comparison_failed" }, + { LMP_PASSKEY_FAILED, "LMP_passkey_failed" }, + { LMP_OOB_FAILED, "LMP_oob_failed" }, + { LMP_KEYPRESS_NOTIFICATION, "LMP_keypress_notification" }, + { LMP_POWER_CONTROL_REQ, "LMP_power_control_req" }, + { LMP_POWER_CONTROL_RES, "LMP_power_control_res" }, + { 0, NULL } +}; + +/* LMP error codes */ +static const value_string error_code[] = { + { 0x00, "Success" }, + { 0x01, "Unknown HCI Command" }, + { 0x02, "Unknown Connection Identifier" }, + { 0x03, "Hardware Failure" }, + { 0x04, "Page Timeout" }, + { 0x05, "Authentication Failure" }, + { 0x06, "PIN or Key Missing" }, + { 0x07, "Memory Capacity Exceeded" }, + { 0x08, "Connection Timeout" }, + { 0x09, "Connection Limit Exceeded" }, + { 0x0A, "Synchronous Connection Limit To A Device Exceeded" }, + { 0x0B, "ACL Connection Already Exists" }, + { 0x0C, "Command Disallowed" }, + { 0x0D, "Connection Rejected due to Limited Resources" }, + { 0x0E, "Connection Rejected Due To Security Reasons" }, + { 0x0F, "Connection Rejected due to Unacceptable BD_ADDR" }, + { 0x10, "Connection Accept Timeout Exceeded" }, + { 0x11, "Unsupported Feature or Parameter Value" }, + { 0x12, "Invalid HCI Command Parameters" }, + { 0x13, "Remote User Terminated Connection" }, + { 0x14, "Remote Device Terminated Connection due to Low Resources" }, + { 0x15, "Remote Device Terminated Connection due to Power Off" }, + { 0x16, "Connection Terminated By Local Host" }, + { 0x17, "Repeated Attempts" }, + { 0x18, "Pairing Not Allowed" }, + { 0x19, "Unknown LMP PDU" }, + { 0x1A, "Unsupported Remote Feature / Unsupported LMP Feature" }, + { 0x1B, "SCO Offset Rejected" }, + { 0x1C, "SCO Interval Rejected" }, + { 0x1D, "SCO Air Mode Rejected" }, + { 0x1E, "Invalid LMP Parameters" }, + { 0x1F, "Unspecified Error" }, + { 0x20, "Unsupported LMP Parameter Value" }, + { 0x21, "Role Change Not Allowed" }, + { 0x22, "LMP Response Timeout" }, + { 0x23, "LMP Error Transaction Collision" }, + { 0x24, "LMP PDU Not Allowed" }, + { 0x25, "Encryption Mode Not Acceptable" }, + { 0x26, "Link Key Can Not be Changed" }, + { 0x27, "Requested QoS Not Supported" }, + { 0x28, "Instant Passed" }, + { 0x29, "Pairing With Unit Key Not Supported" }, + { 0x2A, "Different Transaction Collision" }, + { 0x2B, "Reserved" }, + { 0x2C, "QoS Unacceptable Parameter" }, + { 0x2D, "QoS Rejected" }, + { 0x2E, "Channel Classification Not Supported" }, + { 0x2F, "Insufficient Security" }, + { 0x30, "Parameter Out Of Mandatory Range" }, + { 0x31, "Reserved" }, + { 0x32, "Role Switch Pending" }, + { 0x33, "Reserved" }, + { 0x34, "Reserved Slot Violation" }, + { 0x35, "Role Switch Failed" }, + { 0x36, "Extended Inquiry Response Too Large" }, + { 0x37, "Secure Simple Pairing Not Supported By Host." }, + { 0x38, "Host Busy - Pairing" }, + { 0x39, "Connection Rejected due to No Suitable Channel Found" }, + { 0, NULL } +}; + +static const value_string encryption_mode[] = { + { 0, "no encryption" }, + { 1, "encryption" }, + { 2, "encryption" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string access_scheme[] = { + { 0, "polling technique" }, + /* 1 - 15 reserved */ + { 0, NULL } +}; + +static const value_string packet_size[] = { + { 0, "no packet-size preference available" }, + { 1, "use 1-slot packets" }, + { 2, "use 3-slot packets" }, + { 3, "use 5-slot packets" }, + { 0, NULL } +}; + +static const value_string edr_type[] = { + { 0, "use DM1 packets" }, + { 1, "use 2 Mbps packets" }, + { 2, "use 3 Mbps packets" }, + /* 3 reserved */ + { 0, NULL } +}; + +static const value_string versnr[] = { + { 0, "Bluetooth Core Specification 1.0b" }, + { 1, "Bluetooth Core Specification 1.1" }, + { 2, "Bluetooth Core Specification 1.2" }, + { 3, "Bluetooth Core Specification 2.0 + EDR" }, + { 4, "Bluetooth Core Specification 2.1 + EDR" }, + { 5, "Bluetooth Core Specification 3.0 + HS" }, + /* 6 - 255 reserved */ + { 0, NULL } +}; + +static const value_string compid[] = { + { 0, "Ericsson Technology Licensing" }, + { 1, "Nokia Mobile Phones" }, + { 2, "Intel Corp." }, + { 3, "IBM Corp." }, + { 4, "Toshiba Corp." }, + { 5, "3Com" }, + { 6, "Microsoft" }, + { 7, "Lucent" }, + { 8, "Motorola" }, + { 9, "Infineon Technologies AG" }, + { 10, "Cambridge Silicon Radio" }, + { 11, "Silicon Wave" }, + { 12, "Digianswer A/S" }, + { 13, "Texas Instruments Inc." }, + { 14, "Parthus Technologies Inc." }, + { 15, "Broadcom Corporation" }, + { 16, "Mitel Semiconductor" }, + { 17, "Widcomm, Inc." }, + { 18, "Zeevo, Inc." }, + { 19, "Atmel Corporation" }, + { 20, "Mitsubishi Electric Corporation" }, + { 21, "RTX Telecom A/S" }, + { 22, "KC Technology Inc." }, + { 23, "Newlogic" }, + { 24, "Transilica, Inc." }, + { 25, "Rohde & Schwarz GmbH & Co. KG" }, + { 26, "TTPCom Limited" }, + { 27, "Signia Technologies, Inc." }, + { 28, "Conexant Systems Inc." }, + { 29, "Qualcomm" }, + { 30, "Inventel" }, + { 31, "AVM Berlin" }, + { 32, "BandSpeed, Inc." }, + { 33, "Mansella Ltd" }, + { 34, "NEC Corporation" }, + { 35, "WavePlus Technology Co., Ltd." }, + { 36, "Alcatel" }, + { 37, "Philips Semiconductors" }, + { 38, "C Technologies" }, + { 39, "Open Interface" }, + { 40, "R F Micro Devices" }, + { 41, "Hitachi Ltd" }, + { 42, "Symbol Technologies, Inc." }, + { 43, "Tenovis" }, + { 44, "Macronix International Co. Ltd." }, + { 45, "GCT Semiconductor" }, + { 46, "Norwood Systems" }, + { 47, "MewTel Technology Inc." }, + { 48, "ST Microelectronics" }, + { 49, "Synopsys" }, + { 50, "Red-M (Communications) Ltd" }, + { 51, "Commil Ltd" }, + { 52, "Computer Access Technology Corporation (CATC)" }, + { 53, "Eclipse (HQ Espana) S.L." }, + { 54, "Renesas Technology Corp." }, + { 55, "Mobilian Corporation" }, + { 56, "Terax" }, + { 57, "Integrated System Solution Corp." }, + { 58, "Matsushita Electric Industrial Co., Ltd." }, + { 59, "Gennum Corporation" }, + { 60, "Research In Motion" }, + { 61, "IPextreme, Inc." }, + { 62, "Systems and Chips, Inc" }, + { 63, "Bluetooth SIG, Inc" }, + { 64, "Seiko Epson Corporation" }, + { 65, "Integrated Silicon Solution Taiwan, Inc." }, + { 66, "CONWISE Technology Corporation Ltd" }, + { 67, "PARROT SA" }, + { 68, "Socket Mobile" }, + { 69, "Atheros Communications, Inc." }, + { 70, "MediaTek, Inc." }, + { 71, "Bluegiga (tentative)" }, + { 72, "Marvell Technology Group Ltd." }, + { 73, "3DSP Corporation" }, + { 74, "Accel Semiconductor Ltd." }, + { 75, "Continental Automotive Systems" }, + { 76, "Apple, Inc." }, + { 77, "Staccato Communications, Inc." }, + { 78, "Avago Technologies" }, + { 79, "APT Ltd." }, + { 80, "SiRF Technology, Inc." }, + { 81, "Tzero Technologies, Inc." }, + { 82, "J&M Corporation" }, + { 83, "Free2move AB" }, + /* 84 - 65534 reserved */ + { 65535, "test" }, + { 0, NULL } +}; + +static const value_string sco_packet[] = { + { 0, "HV1" }, + { 1, "HV2" }, + { 2, "HV3" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string air_mode[] = { + { 0, "mu-law log" }, + { 1, "A-law log" }, + { 2, "CVSD" }, + { 3, "transparent data" }, + /* 4 - 255 reserved */ + { 0, NULL } +}; + +static const value_string paging_scheme[] = { + { 0, "mandatory scheme" }, + /* 1 - 255 reserved */ + { 0, NULL } +}; + +static const value_string paging_scheme_settings[] = { + /* for mandatory scheme: */ + { 0, "R0" }, + { 1, "R1" }, + { 2, "R2" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string afh_mode[] = { + { 0, "AFH disabled" }, + { 1, "AFH enabled" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string features_page[] = { + { 0, "standard features" }, + /* 1 - 255 other feature pages */ + { 0, NULL } +}; + +static const value_string packet_type_table[] = { + { 0, "1 Mbps only" }, + { 1, "2/3 Mbps" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string negotiation_state[] = { + { 0, "Initiate negotiation" }, + { 1, "The latest received set of negotiable parameters were possible but these parameters are preferred." }, + { 2, "The latest received set of negotiable parameters would cause a reserved slot violation." }, + { 3, "The latest received set of negotiable parameters would cause a latency violation." }, + { 4, "The latest received set of negotiable parameters are not supported." }, + /* 5 - 255 reserved */ + { 0, NULL } +}; + +static const value_string afh_reporting_mode[] = { + { 0, "AFH reporting disabled" }, + { 1, "AFH reporting enabled" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string io_capabilities[] = { + { 0, "Display Only" }, + { 1, "Display Yes/No" }, + { 2, "Keyboard Only" }, + { 3, "No Input/No Output" }, + /* 4 - 255 reserved */ + { 0, NULL } +}; + +static const value_string oob_auth_data[] = { + { 0, "No OOB Authentication Data received" }, + { 1, "OOB Authentication Data received" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string auth_requirements[] = { + { 0x00, "MITM Protection Not Required - No Bonding" }, + { 0x01, "MITM Protection Required - No Bonding" }, + { 0x02, "MITM Protection Not Required - Dedicated Bonding" }, + { 0x03, "MITM Protection Required - Dedicated Bonding" }, + { 0x04, "MITM Protection Not Required - General Bonding" }, + { 0x05, "MITM Protection Required - General Bonding" }, + /* 0x06 - 0xff reserved */ + { 0, NULL } +}; + +static const value_string power_adjust_req[] = { + { 0, "decrement power one step" }, + { 1, "increment power one step" }, + { 2, "increase to maximum power" }, + /* 3 - 255 reserved */ + { 0, NULL } +}; + +static const value_string power_adjust_res[] = { + { 0, "not supported" }, + { 1, "changed one step (not min or max)" }, + { 2, "max power" }, + { 3, "min power" }, + /* 4 - 255 reserved */ + { 0, NULL } +}; + +static const value_string test_scenario[] = { + { 0, "Pause Test Mode" }, + { 1, "Transmitter test - 0 pattern" }, + { 2, "Transmitter test - 1 pattern" }, + { 3, "Transmitter test - 1010 pattern" }, + { 4, "Pseudorandom bit sequence" }, + { 5, "Closed Loop Back - ACL packets" }, + { 6, "Closed Loop Back - Synchronous packets" }, + { 7, "ACL Packets without whitening" }, + { 8, "Synchronous Packets without whitening" }, + { 9, "Transmitter test - 1111 0000 pattern" }, + /* 10 - 254 reserved */ + { 255, "Exit Test Mode" }, + { 0, NULL } +}; + +static const value_string hopping_mode[] = { + { 0, "RX/TX on single frequency" }, + { 1, "Normal hopping" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string power_control_mode[] = { + { 0, "fixed TX output power" }, + { 1, "adaptive power control" }, + /* 2 - 255 reserved */ + { 0, NULL } +}; + +static const value_string esco_packet_type[] = { + { 0x00, "NULL/POLL" }, + { 0x07, "EV3" }, + { 0x0C, "EV4" }, + { 0x0D, "EV5" }, + { 0x26, "2-EV3" }, + { 0x2C, "2-EV5" }, + { 0x37, "3-EV3" }, + { 0x3D, "3-EV5" }, + /* other values reserved */ + { 0, NULL } +}; + +static const value_string notification_value[] = { + { 0, "passkey entry started" }, + { 1, "passkey digit entered" }, + { 2, "passkey digit erased" }, + { 3, "passkey cleared" }, + { 4, "passkey entry completed" }, + /* 5 - 255 reserved */ + { 0, NULL } +}; + +/* initialize the subtree pointers */ +static gint ett_lmp = -1; +static gint ett_lmp_pwradjres = -1; +static gint ett_lmp_rate = -1; +static gint ett_lmp_timectrl = -1; + +/* LMP PDUs with short opcodes */ + +void +dissect_name_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_nameoffset, tvb, offset, 1, ENC_NA); +} + +void +dissect_name_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_nameoffset, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_namelen, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_namefrag, tvb, offset, 14, ENC_ASCII|ENC_NA); +} + +void +dissect_accepted(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_NA); +} + +void +dissect_not_accepted(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_clkoffset_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_clkoffset_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_clkoffset, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_detach(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_in_rand(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_comb_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_unit_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_key, tvb, offset, 16, ENC_NA); +} + +void +dissect_au_rand(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_sres(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 4); + + proto_tree_add_item(tree, hf_lmp_authres, tvb, offset, 4, ENC_NA); +} + +void +dissect_temp_rand(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_temp_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_key, tvb, offset, 16, ENC_NA); +} + +void +dissect_encryption_mode_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_cryptmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_encryption_key_size_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_keysz, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_start_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_rand, tvb, offset, 16, ENC_NA); +} + +void +dissect_stop_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_switch_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 4); + + proto_tree_add_item(tree, hf_lmp_swinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); +} + +void +dissect_hold(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 6); + + proto_tree_add_item(tree, hf_lmp_htime, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_hinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); +} + +void +dissect_hold_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 6); + + proto_tree_add_item(tree, hf_lmp_htime, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_hinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); +} + +void +dissect_sniff_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 10); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 9); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_dsniff, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_tsniff, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffatt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffto, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_unsniff_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_park_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_tb, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nb, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_deltab, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_araddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_nbsleep, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_dbsleep, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_daccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_taccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_naccslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_npoll, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_accscheme, tvb, offset, 1, ENC_NA); +} + +void +dissect_set_broadcast_scan_window(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 6); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 4); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + } + + proto_tree_add_item(tree, hf_lmp_bsw, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_modify_beacon(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 13); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 11); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 11); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 9); + } + + proto_tree_add_item(tree, hf_lmp_tb, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nb, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_deltab, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_daccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_taccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_naccslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_npoll, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maccess, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_accscheme, tvb, offset, 1, ENC_NA); +} + +void +dissect_unpark_bd_addr_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + proto_item *item; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 15); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 15); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 13); + } + + proto_tree_add_item(tree, hf_lmp_ltaddr1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_bdaddr1, tvb, offset, 6, ENC_LITTLE_ENDIAN); + offset += 6; + + proto_tree_add_item(tree, hf_lmp_bdaddr2, tvb, offset, 6, ENC_LITTLE_ENDIAN); + offset += 6; +} + +void +dissect_unpark_pm_addr_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + int db_present; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + + /* bit0 of timing control flags indicates presence of db */ + db_present = tvb_get_guint8(tvb, offset) & 0x01; + offset += 1; + + if (db_present) { + DISSECTOR_ASSERT(len == 15); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 13); + + proto_tree_add_item(tree, hf_lmp_db, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } else { + DISSECTOR_ASSERT(len == 13); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 11); + } + + proto_tree_add_item(tree, hf_lmp_ltaddr1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_ltaddr3, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr4, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr3, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr4, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_ltaddr5, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_lmp_ltaddr6, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr5, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr6, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_ltaddr7, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pmaddr7, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_incr_power_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + + /* skipping one byte "for future use" */ +} + +void +dissect_decr_power_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + + /* skipping one byte "for future use" */ +} + +void +dissect_max_power(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_min_power(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_auto_rate(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_preferred_rate(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + proto_item *rate_item; + proto_tree *rate_tree; + + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + rate_item = proto_tree_add_item(tree, hf_lmp_rate, tvb, offset, 1, ENC_LITTLE_ENDIAN); + rate_tree = proto_item_add_subtree(rate_item, ett_lmp_rate); + + proto_tree_add_item(rate_tree, hf_lmp_rate_fec, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(rate_tree, hf_lmp_rate_size, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(rate_tree, hf_lmp_rate_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(rate_tree, hf_lmp_rate_edrsize, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_version_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 6); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 5); + + proto_tree_add_item(tree, hf_lmp_versnr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_compid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_subversnr, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_version_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 6); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 5); + + proto_tree_add_item(tree, hf_lmp_versnr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_compid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_subversnr, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_features_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 8); + + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_features_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 8); + + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_quality_of_service(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_pollintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nbc, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_quality_of_service_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_pollintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_nbc, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_sco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 6); + + proto_tree_add_item(tree, hf_lmp_scohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_dsco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_tsco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_scopkt, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_airmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_remove_sco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_scohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_max_slot(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_maxslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_max_slot_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_maxslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_timing_accuracy_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_timing_accuracy_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_drift, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_jitter, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_setup_complete(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_use_semi_permanent_key(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_host_connection_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_slot_offset(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 8); + + proto_tree_add_item(tree, hf_lmp_slotoffset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_bdaddr, tvb, offset, 6, ENC_LITTLE_ENDIAN); +} + +void +dissect_page_mode_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_pagesch, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pssettings, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_page_scan_mode_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_pagesch, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pssettings, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_supervision_timeout(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_suptimeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_test_activate(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_test_control(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 10); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 9); + + /* FIXME these fields should all be XORed with 0x55. . . */ + + proto_tree_add_item(tree, hf_lmp_testscen, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_hopmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_txfreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_rxfreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pcmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pollper, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_pkttype, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_testlen, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_encryption_key_size_mask_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 1); +} + +void +dissect_encryption_key_size_mask_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_ksmask, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_set_afh(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 16); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 15); + + proto_tree_add_item(tree, hf_lmp_afhinst, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_lmp_afhmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_afhchmap, tvb, offset, 10, ENC_NA); +} + +void +dissect_encapsulated_header(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_encmaj, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_encmin, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_enclen, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_encapsulated_payload(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_encdata, tvb, offset, 16, ENC_NA); +} + +void +dissect_simple_pairing_confirm(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_commit, tvb, offset, 16, ENC_NA); +} + +void +dissect_simple_pairing_number(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_nonce, tvb, offset, 16, ENC_NA); +} + +void +dissect_dhkey_check(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 17); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 16); + + proto_tree_add_item(tree, hf_lmp_confirm, tvb, offset, 16, ENC_NA); +} + +/* LMP PDUs with extended opcodes */ + +void +dissect_accepted_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_eopinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_not_accepted_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_opinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_eopinre, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_features_req_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 12); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 10); + + proto_tree_add_item(tree, hf_lmp_fpage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maxsp, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* + * extended features might need to be different from hf_lmp_features + * if hf_lmp_features is broken out + */ + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_features_res_ext(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 12); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 10); + + proto_tree_add_item(tree, hf_lmp_fpage, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_maxsp, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* + * extended features might need to be different from hf_lmp_features + * if hf_lmp_features is broken out + */ + proto_tree_add_item(tree, hf_lmp_features, tvb, offset, 8, ENC_NA); +} + +void +dissect_packet_type_table_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_pkttypetbl, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_esco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 16); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 14); + + proto_tree_add_item(tree, hf_lmp_escohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escoltaddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_bitmask(tree, tvb, offset, hf_lmp_timectrl, + ett_lmp_timectrl, timectrl_fields, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_desco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_tesco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_wesco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escotypems, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escotypesm, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_escolenms, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_escolensm, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_airmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_negstate, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_remove_esco_link_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 4); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 2); + + proto_tree_add_item(tree, hf_lmp_escohdl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_err, tvb, offset, 1, ENC_NA); +} + +void +dissect_channel_classification_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 7); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 5); + + proto_tree_add_item(tree, hf_lmp_afhrptmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_afhminintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_afhmaxintvl, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_channel_classification(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 12); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 10); + + proto_tree_add_item(tree, hf_lmp_afhclass, tvb, offset, 10, ENC_NA); +} + +void +dissect_sniff_subrating_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 7); + + proto_tree_add_item(tree, hf_lmp_maxss, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_minsmt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffsi, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_sniff_subrating_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 9); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 7); + + proto_tree_add_item(tree, hf_lmp_maxss, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_minsmt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_lmp_sniffsi, tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_pause_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_resume_encryption_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_io_capability_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_iocaps, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_oobauthdata, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_authreqs, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_io_capability_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 5); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 3); + + proto_tree_add_item(tree, hf_lmp_iocaps, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_oobauthdata, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(tree, hf_lmp_authreqs, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_numeric_comparison_failed(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_passkey_failed(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_oob_failed(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 2); +} + +void +dissect_keypress_notification(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_nottype, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_power_control_req(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + proto_tree_add_item(tree, hf_lmp_pwradjreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +void +dissect_power_control_res(proto_tree *tree, tvbuff_t *tvb, int offset, int len) +{ + proto_item *pa_item; + proto_tree *pa_tree; + + DISSECTOR_ASSERT(len == 3); + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + pa_item = proto_tree_add_item(tree, hf_lmp_pwradjres, tvb, offset, 1, ENC_LITTLE_ENDIAN); + pa_tree = proto_item_add_subtree(pa_item, ett_lmp_pwradjres); + + proto_tree_add_item(pa_tree, hf_lmp_pwradj_gfsk, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pa_tree, hf_lmp_pwradj_dqpsk, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pa_tree, hf_lmp_pwradj_8dpsk, tvb, offset, 1, ENC_LITTLE_ENDIAN); +} + +/* Link Manager Protocol */ +static void +dissect_btlmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *lmp_item; + proto_tree *lmp_tree; + int offset; + int len; + int op; /* opcode */ + int eop; /* extended opcode */ + + offset = 0; + len = tvb_length(tvb); + + DISSECTOR_ASSERT(len >= 1); + + /* make entries in protocol column and info column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LMP"); + + /* clear the info column first just in case of type fetching failure. */ + col_clear(pinfo->cinfo, COL_INFO); + + op = tvb_get_guint8(tvb, offset) >> 1; + + if (op == LMP_ESCAPE_4) { + DISSECTOR_ASSERT(len >= 2); + + eop = tvb_get_guint8(tvb, offset + 1); + + col_add_str(pinfo->cinfo, COL_INFO, val_to_str(eop, + opcode, "Unknown Extended Opcode (%d)")); + } else { + col_add_str(pinfo->cinfo, COL_INFO, val_to_str(op, + opcode, "Unknown Opcode (%d)")); + } + + /* see if we are being asked for details */ + if (!tree) + return; + + lmp_item = proto_tree_add_item(tree, proto_btlmp, tvb, offset, -1, ENC_NA); + lmp_tree = proto_item_add_subtree(lmp_item, ett_lmp); + + proto_tree_add_item(lmp_tree, hf_lmp_tid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(lmp_tree, hf_lmp_op, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + switch (op) { + case LMP_NAME_REQ: + dissect_name_req(lmp_tree, tvb, offset, len); + break; + case LMP_NAME_RES: + dissect_name_res(lmp_tree, tvb, offset, len); + break; + case LMP_ACCEPTED: + dissect_accepted(lmp_tree, tvb, offset, len); + break; + case LMP_NOT_ACCEPTED: + dissect_not_accepted(lmp_tree, tvb, offset, len); + break; + case LMP_CLKOFFSET_REQ: + dissect_clkoffset_req(lmp_tree, tvb, offset, len); + break; + case LMP_CLKOFFSET_RES: + dissect_clkoffset_res(lmp_tree, tvb, offset, len); + break; + case LMP_DETACH: + dissect_detach(lmp_tree, tvb, offset, len); + break; + case LMP_IN_RAND: + dissect_in_rand(lmp_tree, tvb, offset, len); + break; + case LMP_COMB_KEY: + dissect_comb_key(lmp_tree, tvb, offset, len); + break; + case LMP_UNIT_KEY: + dissect_unit_key(lmp_tree, tvb, offset, len); + break; + case LMP_AU_RAND: + dissect_au_rand(lmp_tree, tvb, offset, len); + break; + case LMP_SRES: + dissect_sres(lmp_tree, tvb, offset, len); + break; + case LMP_TEMP_RAND: + dissect_temp_rand(lmp_tree, tvb, offset, len); + break; + case LMP_TEMP_KEY: + dissect_temp_key(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_MODE_REQ: + dissect_encryption_mode_req(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_KEY_SIZE_REQ: + dissect_encryption_key_size_req(lmp_tree, tvb, offset, len); + break; + case LMP_START_ENCRYPTION_REQ: + dissect_start_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_STOP_ENCRYPTION_REQ: + dissect_stop_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_SWITCH_REQ: + dissect_switch_req(lmp_tree, tvb, offset, len); + break; + case LMP_HOLD: + dissect_hold(lmp_tree, tvb, offset, len); + break; + case LMP_HOLD_REQ: + dissect_hold_req(lmp_tree, tvb, offset, len); + break; + case LMP_SNIFF_REQ: + dissect_sniff_req(lmp_tree, tvb, offset, len); + break; + case LMP_UNSNIFF_REQ: + dissect_unsniff_req(lmp_tree, tvb, offset, len); + break; + case LMP_PARK_REQ: + dissect_park_req(lmp_tree, tvb, offset, len); + break; + case LMP_SET_BROADCAST_SCAN_WINDOW: + dissect_set_broadcast_scan_window(lmp_tree, tvb, offset, len); + break; + case LMP_MODIFY_BEACON: + dissect_modify_beacon(lmp_tree, tvb, offset, len); + break; + case LMP_UNPARK_BD_ADDR_REQ: + dissect_unpark_bd_addr_req(lmp_tree, tvb, offset, len); + break; + case LMP_UNPARK_PM_ADDR_REQ: + dissect_unpark_pm_addr_req(lmp_tree, tvb, offset, len); + break; + case LMP_INCR_POWER_REQ: + dissect_incr_power_req(lmp_tree, tvb, offset, len); + break; + case LMP_DECR_POWER_REQ: + dissect_decr_power_req(lmp_tree, tvb, offset, len); + break; + case LMP_MAX_POWER: + dissect_max_power(lmp_tree, tvb, offset, len); + break; + case LMP_MIN_POWER: + dissect_min_power(lmp_tree, tvb, offset, len); + break; + case LMP_AUTO_RATE: + dissect_auto_rate(lmp_tree, tvb, offset, len); + break; + case LMP_PREFERRED_RATE: + dissect_preferred_rate(lmp_tree, tvb, offset, len); + break; + case LMP_VERSION_REQ: + dissect_version_req(lmp_tree, tvb, offset, len); + break; + case LMP_VERSION_RES: + dissect_version_res(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_REQ: + dissect_features_req(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_RES: + dissect_features_res(lmp_tree, tvb, offset, len); + break; + case LMP_QUALITY_OF_SERVICE: + dissect_quality_of_service(lmp_tree, tvb, offset, len); + break; + case LMP_QUALITY_OF_SERVICE_REQ: + dissect_quality_of_service_req(lmp_tree, tvb, offset, len); + break; + case LMP_SCO_LINK_REQ: + dissect_sco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_REMOVE_SCO_LINK_REQ: + dissect_remove_sco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_MAX_SLOT: + dissect_max_slot(lmp_tree, tvb, offset, len); + break; + case LMP_MAX_SLOT_REQ: + dissect_max_slot_req(lmp_tree, tvb, offset, len); + break; + case LMP_TIMING_ACCURACY_REQ: + dissect_timing_accuracy_req(lmp_tree, tvb, offset, len); + break; + case LMP_TIMING_ACCURACY_RES: + dissect_timing_accuracy_res(lmp_tree, tvb, offset, len); + break; + case LMP_SETUP_COMPLETE: + dissect_setup_complete(lmp_tree, tvb, offset, len); + break; + case LMP_USE_SEMI_PERMANENT_KEY: + dissect_use_semi_permanent_key(lmp_tree, tvb, offset, len); + break; + case LMP_HOST_CONNECTION_REQ: + dissect_host_connection_req(lmp_tree, tvb, offset, len); + break; + case LMP_SLOT_OFFSET: + dissect_slot_offset(lmp_tree, tvb, offset, len); + break; + case LMP_PAGE_MODE_REQ: + dissect_page_mode_req(lmp_tree, tvb, offset, len); + break; + case LMP_PAGE_SCAN_MODE_REQ: + dissect_page_scan_mode_req(lmp_tree, tvb, offset, len); + break; + case LMP_SUPERVISION_TIMEOUT: + dissect_supervision_timeout(lmp_tree, tvb, offset, len); + break; + case LMP_TEST_ACTIVATE: + dissect_test_activate(lmp_tree, tvb, offset, len); + break; + case LMP_TEST_CONTROL: + dissect_test_control(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_KEY_SIZE_MASK_REQ: + dissect_encryption_key_size_mask_req(lmp_tree, tvb, offset, len); + break; + case LMP_ENCRYPTION_KEY_SIZE_MASK_RES: + dissect_encryption_key_size_mask_res(lmp_tree, tvb, offset, len); + break; + case LMP_SET_AFH: + dissect_set_afh(lmp_tree, tvb, offset, len); + break; + case LMP_ENCAPSULATED_HEADER: + dissect_encapsulated_header(lmp_tree, tvb, offset, len); + break; + case LMP_ENCAPSULATED_PAYLOAD: + dissect_encapsulated_payload(lmp_tree, tvb, offset, len); + break; + case LMP_SIMPLE_PAIRING_CONFIRM: + dissect_simple_pairing_confirm(lmp_tree, tvb, offset, len); + break; + case LMP_SIMPLE_PAIRING_NUMBER: + dissect_simple_pairing_number(lmp_tree, tvb, offset, len); + break; + case LMP_DHKEY_CHECK: + dissect_dhkey_check(lmp_tree, tvb, offset, len); + break; + case LMP_ESCAPE_1: + break; + case LMP_ESCAPE_2: + break; + case LMP_ESCAPE_3: + break; + case LMP_ESCAPE_4: + /* extended opcode */ + DISSECTOR_ASSERT(len >= 2); + proto_tree_add_item(lmp_tree, hf_lmp_eop, tvb, offset, 1, ENC_NA); + offset += 1; + + switch (eop) { + case LMP_ACCEPTED_EXT: + dissect_accepted_ext(lmp_tree, tvb, offset, len); + break; + case LMP_NOT_ACCEPTED_EXT: + dissect_not_accepted_ext(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_REQ_EXT: + dissect_features_req_ext(lmp_tree, tvb, offset, len); + break; + case LMP_FEATURES_RES_EXT: + dissect_features_res_ext(lmp_tree, tvb, offset, len); + break; + case LMP_PACKET_TYPE_TABLE_REQ: + dissect_packet_type_table_req(lmp_tree, tvb, offset, len); + break; + case LMP_ESCO_LINK_REQ: + dissect_esco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_REMOVE_ESCO_LINK_REQ: + dissect_remove_esco_link_req(lmp_tree, tvb, offset, len); + break; + case LMP_CHANNEL_CLASSIFICATION_REQ: + dissect_channel_classification_req(lmp_tree, tvb, offset, len); + break; + case LMP_CHANNEL_CLASSIFICATION: + dissect_channel_classification(lmp_tree, tvb, offset, len); + break; + case LMP_SNIFF_SUBRATING_REQ: + dissect_sniff_subrating_req(lmp_tree, tvb, offset, len); + break; + case LMP_SNIFF_SUBRATING_RES: + dissect_sniff_subrating_res(lmp_tree, tvb, offset, len); + break; + case LMP_PAUSE_ENCRYPTION_REQ: + dissect_pause_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_RESUME_ENCRYPTION_REQ: + dissect_resume_encryption_req(lmp_tree, tvb, offset, len); + break; + case LMP_IO_CAPABILITY_REQ: + dissect_io_capability_req(lmp_tree, tvb, offset, len); + break; + case LMP_IO_CAPABILITY_RES: + dissect_io_capability_res(lmp_tree, tvb, offset, len); + break; + case LMP_NUMERIC_COMPARISON_FAILED: + dissect_numeric_comparison_failed(lmp_tree, tvb, offset, len); + break; + case LMP_PASSKEY_FAILED: + dissect_passkey_failed(lmp_tree, tvb, offset, len); + break; + case LMP_OOB_FAILED: + dissect_oob_failed(lmp_tree, tvb, offset, len); + break; + case LMP_KEYPRESS_NOTIFICATION: + dissect_keypress_notification(lmp_tree, tvb, offset, len); + break; + case LMP_POWER_CONTROL_REQ: + dissect_power_control_req(lmp_tree, tvb, offset, len); + break; + case LMP_POWER_CONTROL_RES: + dissect_power_control_res(lmp_tree, tvb, offset, len); + break; + default: + break; + } + default: + break; + } +}; + +/* register the protocol with Wireshark */ +void +proto_register_btlmp(void) +{ + + /* list of fields */ + static hf_register_info hf[] = { + { &hf_lmp_accscheme, + { "Access Scheme", "btlmp.accscheme", + FT_UINT8, BASE_DEC, VALS(access_scheme), 0xf0, + NULL, HFILL } + }, + { &hf_lmp_afhchmap, + { "AFH Channel Map", "btlmp.afhchmap", + /* could break out individual channels but long */ + FT_BYTES, BASE_NONE, NULL, 0x0, + "Adaptive Frequency Hopping Channel Map", HFILL } + }, + { &hf_lmp_afhclass, + { "AFH Channel Classification", "btlmp.afhclass", + /* could break out individual channels but long */ + FT_BYTES, BASE_NONE, NULL, 0x0, + "Adaptive Frequency Hopping Channel Classification", HFILL } + }, + { &hf_lmp_afhinst, + { "AFH Instant", "btlmp.afhinst", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Adaptive Frequency Hopping Instant (slot)", HFILL } + }, + { &hf_lmp_afhmaxintvl, + { "AFH Max Interval", "btlmp.maxintvl", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Adaptive Maximum Interval in slots", HFILL } + }, + { &hf_lmp_afhminintvl, + { "AFH Min Interval", "btlmp.minintvl", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Adaptive Minimum Interval in slots", HFILL } + }, + { &hf_lmp_afhmode, + { "AFH Mode", "btlmp.afhmode", + FT_UINT8, BASE_DEC, VALS(afh_mode), 0x0, + "Adaptive Frequency Hopping Mode", HFILL } + }, + { &hf_lmp_afhrptmode, + { "AFH Reporting Mode", "btlmp.afhrptmode", + FT_UINT8, BASE_DEC, VALS(afh_reporting_mode), 0x0, + "Adaptive Frequency Hopping Reporting Mode", HFILL } + }, + { &hf_lmp_airmode, + { "Air Mode", "btlmp.airmode", + FT_UINT8, BASE_HEX, VALS(air_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_araddr, + { "AR_ADDR", "btlmp.araddr", + FT_UINT8, BASE_HEX, NULL, 0xfe, + NULL, HFILL } + }, + { &hf_lmp_authreqs, + { "Authentication Requirements", "btlmp.authreqs", + FT_UINT8, BASE_HEX, VALS(auth_requirements), 0xf0, + NULL, HFILL } + }, + { &hf_lmp_authres, + { "Authentication Response", "btlmp.authres", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_bdaddr, + { "BD_ADDR", "btlmp.bdaddr", + FT_UINT64, BASE_HEX, NULL, 0x0000ffffffffffff, + NULL, HFILL } + }, + { &hf_lmp_bdaddr1, + { "BD_ADDR 1", "btlmp.bdaddr", + FT_UINT64, BASE_HEX, NULL, 0x0000ffffffffffff, + NULL, HFILL } + }, + { &hf_lmp_bdaddr2, + { "BD_ADDR2", "btlmp.bdaddr", + FT_UINT64, BASE_HEX, NULL, 0x0000ffffffffffff, + "BD_ADDR 2", HFILL } + }, + { &hf_lmp_bsw, + { "Broadcast Scan Window", "btlmp.bsw", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Broadcast Scan Window in slots", HFILL } + }, + { &hf_lmp_clkoffset, + { "Clock Offset", "btlmp.clkoffset", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Clock Offset in units of 1.25 ms", HFILL } + }, + { &hf_lmp_commit, + { "Commitment Value", "btlmp.commit", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_confirm, + { "Confirmation Value", "btlmp.confirm", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_compid, + { "Company ID", "btlmp.compid", + FT_UINT16, BASE_DEC, VALS(compid), 0x0, + NULL, HFILL } + }, + { &hf_lmp_cryptmode, + { "Encryption Mode", "btlmp.cryptmode", + FT_UINT8, BASE_DEC, VALS(encryption_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_daccess, + { "Daccess", "btlmp.daccess", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Daccess in slots", HFILL } + }, + { &hf_lmp_db, + { "Db", "btlmp.db", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Db in slots", HFILL } + }, + { &hf_lmp_dbsleep, + { "Dbsleep", "btlmp.dbsleep", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_deltab, + { "Deltab", "btlmp.deltab", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Deltab in slots", HFILL } + }, + { &hf_lmp_desco, + { "Desco", "btlmp.desco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Desco in slots", HFILL } + }, + { &hf_lmp_drift, + { "Drift", "btlmp.drift", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Drift in ppm", HFILL } + }, + { &hf_lmp_dsco, + { "Dsco", "btlmp.dsco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Dsco in slots", HFILL } + }, + { &hf_lmp_dsniff, + { "Dsniff", "btlmp.dsniff", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Dsniff in slots", HFILL } + }, + { &hf_lmp_encdata, + { "Encapsulated Data", "btlmp.encdata", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_enclen, + { "Encapsulated Length", "btlmp.enclen", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_encmaj, + { "Encapsulated Major Type", "btlmp.encmaj", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_encmin, + { "Encapsulated Minor Type", "btlmp.encmin", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_eop, + { "Extended Opcode", "btlmp.eop", + FT_UINT8, BASE_DEC, VALS(ext_opcode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_eopinre, + { "In Response To", "btlmp.eopinre", + FT_UINT8, BASE_DEC, VALS(ext_opcode), 0x0, + "Extended Opcode this is in response to", HFILL } + }, + { &hf_lmp_escolenms, + { "Packet Length M -> S", "btlmp.escolenms", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Packet Length in bytes Master to Slave", HFILL } + }, + { &hf_lmp_escolensm, + { "Packet Length S -> M", "btlmp.escolensm", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Packet Length in bytes Slave to Master", HFILL } + }, + { &hf_lmp_escotypems, + { "eSCO Packet Type M -> S", "btlmp.escotypems", + FT_UINT8, BASE_HEX, VALS(esco_packet_type), 0x0, + "eSCO Packet Type Master to Slave", HFILL } + }, + { &hf_lmp_escotypesm, + { "eSCO Packet Type S -> M", "btlmp.escotypesm", + FT_UINT8, BASE_HEX, VALS(esco_packet_type), 0x0, + "eSCO Packet Type Slave to Master", HFILL } + }, + { &hf_lmp_err, + { "Error Code", "btlmp.err", + FT_UINT8, BASE_HEX, VALS(error_code), 0x0, + NULL, HFILL } + }, + { &hf_lmp_escohdl, + { "eSCO Handle", "btlmp.escohdl", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_escoltaddr, + { "eSCO LT_ADDR", "btlmp.escoltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0, + "eSCO Logical Transport Address", HFILL } + }, + { &hf_lmp_features, + { "Features", "btlmp.features", + /* could break out individual features but long */ + FT_BYTES, BASE_NONE, NULL, 0x0, + "Feature Mask", HFILL } + }, + { &hf_lmp_fpage, + { "Features Page", "btlmp.fpage", + FT_UINT8, BASE_DEC, VALS(features_page), 0x0, + NULL, HFILL } + }, + { &hf_lmp_htime, + { "Hold Time", "btlmp.htime", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Hold Time in slots", HFILL } + }, + { &hf_lmp_hinst, + { "Hold Instant", "btlmp.hinst", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Hold Instant (slot)", HFILL } + }, + { &hf_lmp_hopmode, + { "Hopping Mode", "btlmp.hopmode", + FT_UINT8, BASE_DEC, VALS(hopping_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_iocaps, + { "IO Capabilities", "btlmp.iocaps", + FT_UINT8, BASE_DEC, VALS(io_capabilities), 0x0, + "Input/Output Capabilities", HFILL } + }, + { &hf_lmp_jitter, + { "Jitter", "btlmp.jitter", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Jitter in microseconds", HFILL } + }, + { &hf_lmp_key, + { "Key", "btlmp.key", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_keysz, + { "Key Size", "btlmp.keysz", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Key Size in bytes", HFILL } + }, + { &hf_lmp_ksmask, + { "Key Size Mask", "btlmp.ksmask", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_ltaddr1, + { "LT_ADDR 1", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 1", HFILL } + }, + { &hf_lmp_ltaddr2, + { "LT_ADDR 2", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Logical Transport Address 2", HFILL } + }, + { &hf_lmp_ltaddr3, + { "LT_ADDR 3", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 3", HFILL } + }, + { &hf_lmp_ltaddr4, + { "LT_ADDR 4", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Logical Transport Address 4", HFILL } + }, + { &hf_lmp_ltaddr5, + { "LT_ADDR 5", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 5", HFILL } + }, + { &hf_lmp_ltaddr6, + { "LT_ADDR 6", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0xf0, + "Logical Transport Address 6", HFILL } + }, + { &hf_lmp_ltaddr7, + { "LT_ADDR 7", "btlmp.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Logical Transport Address 7", HFILL } + }, + { &hf_lmp_maccess, + { "Maccess", "btlmp.maccess", + FT_UINT8, BASE_HEX, NULL, 0x0f, + "Number of access windows", HFILL } + }, + { &hf_lmp_maxslots, + { "Max Slots", "btlmp.maxslots", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_maxsp, + { "Max Supported Page", "btlmp.maxsp", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Highest extended features page with non-zero bit", HFILL } + }, + { &hf_lmp_maxss, + { "Max Sniff Subrate", "btlmp.maxss", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_minsmt, + { "Min Sniff Mode Timeout", "btlmp.minsmt", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Min Sniff Mode Timeout in slots", HFILL } + }, + { &hf_lmp_naccslots, + { "Nacc-slots", "btlmp.naccslots", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_namefrag, + { "Name Fragment", "btlmp.namefrag", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_namelen, + { "Name Length", "btlmp.namelen", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Name Length in bytes", HFILL } + }, + { &hf_lmp_nameoffset, + { "Name Offset", "btlmp.nameoffset", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Name Offset in bytes", HFILL } + }, + { &hf_lmp_nb, + { "Nb", "btlmp.nb", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_nbc, + { "Nbc", "btlmp.nbc", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_nbsleep, + { "Nbsleep", "btlmp.nbsleep", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_negstate, + { "Negotiation State", "btlmp.negstate", + FT_UINT8, BASE_DEC, VALS(negotiation_state), 0x0, + NULL, HFILL } + }, + { &hf_lmp_nonce, + { "Nonce Value", "btlmp.nonce", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_nottype, + { "Notification Type", "btlmp.nottype", + FT_UINT8, BASE_DEC, VALS(notification_value), 0x0, + NULL, HFILL } + }, + { &hf_lmp_npoll, + { "Npoll", "btlmp.npoll", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_oobauthdata, + { "OOB Authentication Data", "btlmp.oobauthdata", + FT_UINT8, BASE_DEC, VALS(oob_auth_data), 0xfe, + NULL, HFILL } + }, + { &hf_lmp_op, + { "Opcode", "btlmp.op", + FT_UINT8, BASE_DEC, VALS(opcode), 0xfe, + NULL, HFILL } + }, + { &hf_lmp_opinre, + { "In Response To", "btlmp.opinre", + FT_UINT8, BASE_DEC, VALS(opcode), 0x7f, + "Opcode this is in response to", HFILL } + }, + { &hf_lmp_pagesch, + { "Paging Scheme", "btlmp.pagesch", + FT_UINT8, BASE_DEC, VALS(paging_scheme), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pcmode, + { "Power Control Mode", "btlmp.pcmode", + FT_UINT8, BASE_DEC, VALS(power_control_mode), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pkttype, + { "Packet Type", "btlmp.pkttype", + /* FIXME break out further */ + FT_UINT8, BASE_HEX, NULL, 0x0, + "Packet Type", HFILL } + }, + { &hf_lmp_pkttypetbl, + { "Packet Type Table", "btlmp.pkttypetbl", + FT_UINT8, BASE_DEC, VALS(packet_type_table), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr, + { "PM_ADDR", "btlmp.pmaddr", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr1, + { "PM_ADDR 1", "btlmp.pmaddr1", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr2, + { "PM_ADDR 2", "btlmp.pmaddr2", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr3, + { "PM_ADDR 3", "btlmp.pmaddr3", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr4, + { "PM_ADDR 4", "btlmp.pmaddr4", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr5, + { "PM_ADDR 5", "btlmp.pmaddr5", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr6, + { "PM_ADDR 6", "btlmp.pmaddr6", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pmaddr7, + { "PM_ADDR 7", "btlmp.pmaddr7", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pollintvl, + { "Poll Interval", "btlmp.pollintvl", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Poll Interval in slots", HFILL } + }, + { &hf_lmp_pollper, + { "Poll Period", "btlmp.pollper", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Poll Period in units of 1.25 ms", HFILL } + }, + { &hf_lmp_pssettings, + { "Paging Scheme Settings", "btlmp.pssettings", + FT_UINT8, BASE_DEC, VALS(paging_scheme_settings), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pwradjreq, + { "Power Adjustment Request", "btlmp.pwradjreq", + FT_UINT8, BASE_DEC, VALS(power_adjust_req), 0x0, + NULL, HFILL } + }, + { &hf_lmp_pwradjres, + { "Power Adjustment Response", "btlmp.pwradjres", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_pwradj_8dpsk, + { "8DPSK", "btlmp.pwradj_8dpsk", + FT_UINT8, BASE_DEC, VALS(power_adjust_res), 0x30, + "8DPSK Power Adjustment Response", HFILL } + }, + { &hf_lmp_pwradj_dqpsk, + { "DQPSK", "btlmp.pwradj_dqpsk", + FT_UINT8, BASE_DEC, VALS(power_adjust_res), 0x0C, + "DQPSK Power Adjustment Response", HFILL } + }, + { &hf_lmp_pwradj_gfsk, + { "GFSK", "btlmp.pwradj_gfsk", + FT_UINT8, BASE_DEC, VALS(power_adjust_res), 0x03, + "GFSK Power Adjustment Response", HFILL } + }, + { &hf_lmp_rand, + { "Random Number", "btlmp.rand", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_rate, + { "Data Rate", "btlmp.rate", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_rate_fec, + { "FEC", "btlmp.rate.fec", + FT_BOOLEAN, BASE_DEC, TFS(&fec), 0x01, + "Forward Error Correction", HFILL } + }, + { &hf_lmp_rate_size, + { "Packet Size", "btlmp.rate.size", + FT_UINT8, BASE_HEX, VALS(packet_size), 0x06, + "Basic Rate Packet Size", HFILL } + }, + { &hf_lmp_rate_type, + { "EDR Type", "btlmp.rate.type", + FT_UINT8, BASE_HEX, VALS(edr_type), 0x18, + "Enhanced Data Rate type", HFILL } + }, + { &hf_lmp_rate_edrsize, + { "EDR Size", "btlmp.rate.edrsize", + FT_UINT8, BASE_HEX, VALS(packet_size), 0x60, + "Enhanced Data Rate packet size", HFILL } + }, + { &hf_lmp_rxfreq, + { "RX Frequency", "btlmp.rxfreq", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Receive Frequency in MHz above 2402", HFILL } + }, + { &hf_lmp_scohdl, + { "SCO Handle", "btlmp.scohdl", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_scopkt, + { "SCO Packet", "btlmp.scopkt", + FT_UINT8, BASE_DEC, VALS(sco_packet), 0x0, + NULL, HFILL } + }, + { &hf_lmp_slotoffset, + { "Slot Offset", "btlmp.slotoffset", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Slot Offset in microseconds", HFILL } + }, + { &hf_lmp_sniffatt, + { "Sniff Attempt", "btlmp.sniffatt", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Number of receive slots", HFILL } + }, + { &hf_lmp_sniffsi, + { "Sniff Subrating Instant", "btlmp.sniffsi", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Sniff Subrating Instant (slot)", HFILL } + }, + { &hf_lmp_sniffto, + { "Sniff Timeout", "btlmp.sniffto", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Number of receive slots", HFILL } + }, + { &hf_lmp_subversnr, + { "SubVersNr", "btlmp.subversnr", + FT_UINT16, BASE_DEC, NULL, 0x0, + "SubVersion", HFILL } + }, + { &hf_lmp_suptimeout, + { "Supervision Timeout", "btlmp.suptimeout", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Supervision Timeout in slots", HFILL } + }, + { &hf_lmp_swinst, + { "Switch Instant", "btlmp.swinst", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Switch Instant (slot)", HFILL } + }, + { &hf_lmp_taccess, + { "Taccess", "btlmp.taccess", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Taccess in slots", HFILL } + }, + { &hf_lmp_tb, + { "Tb", "btlmp.tb", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Tb in slots", HFILL } + }, + { &hf_lmp_tesco, + { "Tesco", "btlmp.tesco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Tesco in slots", HFILL } + }, + { &hf_lmp_testlen, + { "Test Length", "btlmp.testlen", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of test sequence in bytes", HFILL } + }, + { &hf_lmp_testscen, + { "Test Scenario", "btlmp.testscen", + FT_UINT8, BASE_DEC, VALS(test_scenario), 0x0, + NULL, HFILL } + }, + { &hf_lmp_tid, + { "TID", "btlmp.tid", + FT_BOOLEAN, BASE_DEC, TFS(&tid), 0x01, + "Transaction ID", HFILL } + }, + { &hf_lmp_timectrl, + { "Timing Control Flags", "btlmp.timectrl", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_lmp_time_change, + { "Timing Change", "btlmp.time.change", + FT_BOOLEAN, 8, TFS(&time_change), 0x01, + NULL, HFILL } + }, + { &hf_lmp_time_init, + { "Initialization", "btlmp.time.init", + FT_BOOLEAN, 8, TFS(&time_init), 0x02, + NULL, HFILL } + }, + { &hf_lmp_time_accwin, + { "Access Window", "btlmp.time.accwin", + FT_BOOLEAN, 8, TFS(&time_accwin), 0x04, + NULL, HFILL } + }, + { &hf_lmp_tsco, + { "Tsco", "btlmp.tsco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Tsco in slots", HFILL } + }, + { &hf_lmp_tsniff, + { "Tsniff", "btlmp.tsniff", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Tsniff in slots", HFILL } + }, + { &hf_lmp_txfreq, + { "TX Frequency", "btlmp.txfreq", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Transmit Frequency in MHz above 2402", HFILL } + }, + { &hf_lmp_versnr, + { "VersNr", "btlmp.versnr", + FT_UINT8, BASE_DEC, VALS(versnr), 0x0, + "Version", HFILL } + }, + { &hf_lmp_wesco, + { "Wesco", "btlmp.wesco", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Number of slots in retransmission window", HFILL } + }, + }; + + /* protocol subtree arrays */ + static gint *ett[] = { + &ett_lmp, + &ett_lmp_pwradjres, + &ett_lmp_rate, + &ett_lmp_timectrl, + }; + + /* register the protocol name and description */ + proto_btlmp = proto_register_protocol( + "Bluetooth Link Manager Protocol", /* full name */ + "btlmp", /* short name */ + "btlmp" /* abbreviation (e.g. for filters) */ + ); + + register_dissector("btlmp", dissect_btlmp, proto_btlmp); + + /* register the header fields and subtrees used */ + proto_register_field_array(proto_btlmp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_reg_handoff_btlmp(void) +{ +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/plugin.rc.in b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/plugin.rc.in new file mode 100644 index 0000000..568dc07 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/plugin.rc.in @@ -0,0 +1,34 @@ +#include "winver.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @RC_MODULE_VERSION@ + PRODUCTVERSION @RC_VERSION@ + FILEFLAGSMASK 0x0L +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0" + VALUE "FileDescription", "@PACKAGE@ dissector\0" + VALUE "FileVersion", "@MODULE_VERSION@\0" + VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0" + VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs , Gilbert Ramirez and others\0" + VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0" + VALUE "ProductName", "Wireshark\0" + VALUE "ProductVersion", "@VERSION@\0" + VALUE "Comments", "Build with @MSVC_VARIANT@\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg new file mode 100755 index 0000000..d2efa7c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg.py b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg.py new file mode 100755 index 0000000..060460c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btbredr/tools/make-dissector-reg.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $ + +import os +import sys +import re +import pickle +from stat import * + +VERSION_KEY = '_VERSION' +CUR_VERSION = '$Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $' + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin" or registertype == "plugin_wtap": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by Makefile or Makefile.nmake. + */ +""" +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by the "register.c" target in + * epan/dissectors/Makefile or Makefile.nmake using information in + * epan/dissectors/register-cache.pkl. + * + * You can force this file to be regenerated completely by deleting + * it along with epan/dissectors/register-cache.pkl. + */ +""" +else: + print(("Unknown output type '%s'" % registertype)) + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append(os.path.join(srcdir, file)) + +if len(filenames) < 1: + print("No files found") + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +wtap_reg_regex0 = r"^(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" +wtap_reg_regex1 = r"void\s+(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ( 'wtap_register', re.compile(wtap_reg_regex0) ), + ( 'wtap_register', re.compile(wtap_reg_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION: + cache = {VERSION_KEY: CUR_VERSION} + except: + cache = {VERSION_KEY: CUR_VERSION} + + print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1))) + +# Grep +cache_hits = 0 +cache_misses = 0 +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and filename in cache: + cdict = cache[filename] + if cur_mtime == cdict['mtime']: + cache_hits += 1 +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + regs['wtap_register'].extend(cdict['wtap_register']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache_misses += 1 + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses))) + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print("No protocol registrations found") + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() +regs['wtap_register'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write(preamble) + +# Make the routine to register all protocols +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +elif registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +register_wtap_module(void) +{ +"""); + + for symbol in regs['wtap_register']: + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + reg_code.write(line) + + reg_code.write("}\n"); + reg_code.write("#endif\n"); +else: + reg_code.write(""" +static gulong proto_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['proto_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +static gulong handoff_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['handoff_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return proto_reg_count() + handoff_reg_count();" + reg_code.write(line) + + reg_code.write(""" +}\n +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/AUTHORS b/libbtbb-2015-10-R1/wireshark/plugins/btle/AUTHORS new file mode 100644 index 0000000..7658f97 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/AUTHORS @@ -0,0 +1,3 @@ +Authors: +Mike Ryan +Michael Ossmann diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/CMakeLists.txt b/libbtbb-2015-10-R1/wireshark/plugins/btle/CMakeLists.txt new file mode 100644 index 0000000..1e71b1f --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/CMakeLists.txt @@ -0,0 +1,88 @@ +# CMakeLists.txt +# +# $Id: CMakeLists.txt 31995 2010-02-24 22:32:10Z jmayer $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +project(btle-wireshark-plugin C) + +cmake_minimum_required(VERSION 2.6) +set(CMAKE_BACKWARDS_COMPATIBILITY 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +IF ( NOT CMAKE_INSTALL_LIBDIR ) + set(CMAKE_INSTALL_LIBDIR ~/.wireshark/plugins) +ENDIF ( NOT CMAKE_INSTALL_LIBDIR ) +MESSAGE (STATUS "Plugin will be installed in: ${CMAKE_INSTALL_LIBDIR}") + +INCLUDE(UseMakeDissectorReg) + +set(GLIB2_MIN_VERSION 2.4.0) + +find_package(GLIB2) +include_directories (${GLIB2_INCLUDE_DIRS}) + +find_package(Wireshark) +include_directories (${WIRESHARK_INCLUDE_DIRS}) + +set(LINK_MODE_LIB SHARED) +set(LINK_MODE_MODULE MODULE) + + +set(DISSECTOR_SRC + packet-btle.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} +) + +set(CLEAN_FILES + ${PLUGIN_FILES} +) + +if (WERROR) + set_source_files_properties( + ${CLEAN_FILES} + PROPERTIES + COMPILE_FLAGS -Werror + ) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +register_dissector_files(plugin.c + plugin + ${DISSECTOR_SRC} +) + +add_library(btle ${LINK_MODE_MODULE} + ${PLUGIN_FILES} +) +set_target_properties(btle PROPERTIES PREFIX "") +set_target_properties(btle PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}") + +target_link_libraries(btle wireshark) + +install(TARGETS btle + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/ NAMELINK_SKIP +) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btle/COPYING new file mode 100644 index 0000000..aa0aea5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.am b/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.am new file mode 100644 index 0000000..d863ce5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.am @@ -0,0 +1,125 @@ +# Makefile.am +# Automake file for AgentX plugin +# +# $Id: Makefile.am 24488 2008-02-27 16:18:30Z stig $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +INCLUDES = -I$(top_srcdir) -I$(includedir) + +include Makefile.common + +#if HAVE_WARNINGS_AS_ERRORS +#AM_CFLAGS = -Werror +#endif + +plugindir = @plugindir@ + +plugin_LTLIBRARIES = btle.la +btle_la_SOURCES = \ + plugin.c \ + moduleinfo.h \ + $(DISSECTOR_SRC) \ + $(DISSECTOR_SUPPORT_SRC) \ + $(DISSECTOR_INCLUDES) +btle_la_LDFLAGS = -module -avoid-version +btle_la_LIBADD = @PLUGIN_LIBS@ + +# Libs must be cleared, or else libtool won't create a shared module. +# If your module needs to be linked against any particular libraries, +# add them here. +LIBS = + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ + $(top_srcdir)/tools/make-dissector-reg.py + @if test -n "$(PYTHON)"; then \ + echo Making plugin.c with python ; \ + $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + plugin $(DISSECTOR_SRC) ; \ + else \ + echo Making plugin.c with shell script ; \ + $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + $(plugin_src) plugin $(DISSECTOR_SRC) ; \ + fi + +# +# Currently plugin.c can be included in the distribution because +# we always build all protocol dissectors. We used to have to check +# whether or not to build the snmp dissector. If we again need to +# variably build something, making plugin.c non-portable, uncomment +# the dist-hook line below. +# +# Oh, yuk. We don't want to include "plugin.c" in the distribution, as +# its contents depend on the configuration, and therefore we want it +# to be built when the first "make" is done; however, Automake insists +# on putting *all* source into the distribution. +# +# We work around this by having a "dist-hook" rule that deletes +# "plugin.c", so that "dist" won't pick it up. +# +#dist-hook: +# @rm -f $(distdir)/plugin.c + +CLEANFILES = \ + btle \ + *~ + +MAINTAINERCLEANFILES = \ + Makefile.in \ + plugin.c + +EXTRA_DIST = \ + Makefile.common \ + Makefile.nmake \ + moduleinfo.nmake \ + plugin.rc.in diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.common b/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.common new file mode 100644 index 0000000..644f6c8 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.common @@ -0,0 +1,39 @@ +# Makefile.common for AgentX plugin +# Contains the stuff from Makefile.am and Makefile.nmake that is +# a) common to both files and +# b) portable between both files +# +# $Id: Makefile.common 23848 2007-12-12 22:10:50Z jake $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# the name of the plugin +PLUGIN_NAME = btle + +# the dissector sources (without any helpers) +DISSECTOR_SRC = \ + packet-btle.c + +# corresponding headers +DISSECTOR_INCLUDES = + +# Dissector helpers. They're included in the source files in this +# directory, but they're not dissectors themselves, i.e. they're not +# used to generate "plugin.c". +DISSECTOR_SUPPORT_SRC = diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.nmake b/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.nmake new file mode 100644 index 0000000..857e435 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/Makefile.nmake @@ -0,0 +1,100 @@ +# Makefile.nmake +# nmake file for Wireshark plugin +# +# $Id: Makefile.nmake 24520 2008-03-01 12:31:01Z jake $ +# + +include ..\..\config.nmake +include moduleinfo.nmake + +include Makefile.common + +CFLAGS=/WX /DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \ + /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS) + +.c.obj:: + $(CC) $(CFLAGS) -Fd.\ -c $< + +LDFLAGS = $(PLUGIN_LDFLAGS) + +!IFDEF ENABLE_LIBWIRESHARK +LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib +CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS) + +DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj) + +DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj) + +OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) plugin.obj + +RESOURCE=$(PLUGIN_NAME).res + +all: $(PLUGIN_NAME).dll + +$(PLUGIN_NAME).rc : moduleinfo.nmake + sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ \ + -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ \ + -e s/@RC_VERSION@/$(RC_VERSION)/ \ + -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ \ + -e s/@PACKAGE@/$(PACKAGE)/ \ + -e s/@VERSION@/$(VERSION)/ \ + -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ \ + < plugin.rc.in > $@ + +$(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE) + link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \ + $(GLIB_LIBS) $(RESOURCE) + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +!IFDEF PYTHON +plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg.py + @echo Making plugin.c (using python) + @$(PYTHON) "../../tools/make-dissector-reg.py" . plugin $(DISSECTOR_SRC) +!ELSE +plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg + @echo Making plugin.c (using sh) + @$(SH) ../../tools/make-dissector-reg . plugin $(DISSECTOR_SRC) +!ENDIF + +!ENDIF + +clean: + rm -f $(OBJECTS) $(RESOURCE) plugin.c *.pdb \ + $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib \ + $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc + +distclean: clean + +maintainer-clean: distclean diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/README b/libbtbb-2015-10-R1/wireshark/plugins/btle/README new file mode 100644 index 0000000..b3674f4 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/README @@ -0,0 +1,61 @@ +BTLE Wireshark plugin +===================== + +This plugin is no longer in use, it has been merged in to the Wireshark source +tree as of release 1.12. + + +This is the Bluetooth Low Energy plugin for Wireshark. + +To build this on Debian/Ubuntu/BackTrack linux distributions: + sudo apt-get install wireshark-dev wireshark + cd libbtbb/wireshark/plugins/btle/ + cmake . + make + make install + +This will install to the .wireshark/ in your home directory. To override +this set the DESTDIR environment variable when running cmake. + +PPI Support (Patch) +------------------- + +Ubertooth records capture frequency, internal clock state, and certain +other metadata about packets in a PPI header. It is not possible to add +PPI support in an external plugin, so if you wish to access these fields +you must patch Wireshark. + +The patch wireshark-1.8-btle-ppi.patch was built against the Ubuntu +12.10 Quantal Wireshark package. It can be added to the Ubuntu package +source or applied directly to vanilla Wireshark. + +To build a .deb on Ubuntu, follow these instructions: + + mkdir wireshark && cd wireshark + apt-get source wireshark + cp wireshark-1.8-btle-ppi.patch wireshark-1.8.2/debian/patches + echo wireshark-1.8-btle-ppi.patch >> wireshark-1.8.2/debian/patches/series + cd wireshark-1.8.2 + dpkg-buildpackage -rfakeroot + +The .deb will be created in the wireshark directory, and it can be +installed with dpkg -i. + +Attribute Protocol Support +-------------------------- + +Wireshark trunk has native support for the Bluetooth Attribute protocol. +If you are using a distro package that does not support it, install the +plugin found in the btatt directory (above this directory). + +If the protocol column of non-empty data packets says L2CAP, you should +install the plugin. If it says ATT, you do not need the plugin. If it +says something else, please email me! + +Bluetooth Security Manager Protocol +----------------------------------- + +All security-related exchanges (pairing and identity resolution) take +place over the Bluetooth Security Manager (SM) protocol, which runs on +L2CAP. If you would like to dissect these packets, build and install the +plugin found in the btsm directory above this directory. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING new file mode 100644 index 0000000..53b6b71 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING-CMAKE-SCRIPTS b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..280ed6c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,27 @@ +Copyright notice for the files copied from +http://www.opensync.org/browser/branches/3rd-party-cmake-modules/modules + +$Id: COPYING-CMAKE-SCRIPTS 34248 2010-09-25 15:38:12Z jmayer $ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindGLIB2.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindGLIB2.cmake new file mode 100644 index 0000000..ae7badd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindGLIB2.cmake @@ -0,0 +1,238 @@ +# +# $Id: FindGLIB2.cmake 34248 2010-09-25 15:38:12Z jmayer $ +# +# - Try to find GLib2 +# Once done this will define +# +# GLIB2_FOUND - system has GLib2 +# GLIB2_INCLUDE_DIRS - the GLib2 include directory +# GLIB2_LIBRARIES - Link these to use GLib2 +# +# HAVE_GLIB_GREGEX_H glib has gregex.h header and +# supports g_regex_match_simple +# +# Copyright (c) 2006 Andreas Schneider +# Copyright (c) 2006 Philippe Bernery +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Alban Browaeys +# Copyright (c) 2008 Michael Bell +# Copyright (c) 2008-2009 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +IF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + # in cache already + SET(GLIB2_FOUND TRUE) +ELSE (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + + INCLUDE(FindPkgConfig) + + ## Glib + IF ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) + ELSE ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) + ENDIF ( GLIB2_FIND_REQUIRED ) + + IF ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0>=${GLIB2_MIN_VERSION} ) + ELSE ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0 ) + ENDIF ( GLIB2_MIN_VERSION ) + IF ( PKG_CONFIG_FOUND ) + IF ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( GLIB2_FOUND ) + ENDIF ( PKG_CONFIG_FOUND ) + + # Look for glib2 include dir and libraries w/o pkgconfig + IF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( + _glibconfig_include_DIR + NAMES + glibconfig.h + PATHS + /opt/gnome/lib64 + /opt/gnome/lib + /opt/lib/ + /opt/local/lib + /sw/lib/ + /usr/lib64 + /usr/lib + /usr/local/include + ${CMAKE_LIBRARY_PATH} + PATH_SUFFIXES + glib-2.0/include + ) + + FIND_PATH( + _glib2_include_DIR + NAMES + glib.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + PATH_SUFFIXES + glib-2.0 + ) + + #MESSAGE(STATUS "Glib headers: ${_glib2_include_DIR}") + + FIND_LIBRARY( + _glib2_link_DIR + NAMES + glib-2.0 + glib + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + IF ( _glib2_include_DIR AND _glib2_link_DIR ) + SET ( _glib2_FOUND TRUE ) + ENDIF ( _glib2_include_DIR AND _glib2_link_DIR ) + + + IF ( _glib2_FOUND ) + SET ( GLIB2_INCLUDE_DIRS ${_glib2_include_DIR} ${_glibconfig_include_DIR} ) + SET ( GLIB2_LIBRARIES ${_glib2_link_DIR} ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( _glib2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( _glib2_FOUND ) + + # Handle dependencies + # libintl + IF ( NOT LIBINTL_FOUND ) + FIND_PATH(LIBINTL_INCLUDE_DIR + NAMES + libintl.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + ) + + FIND_LIBRARY(LIBINTL_LIBRARY + NAMES + intl + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/local/lib + /usr/lib + ) + + IF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + SET (LIBINTL_FOUND TRUE) + ENDIF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + ENDIF ( NOT LIBINTL_FOUND ) + + # libiconv + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR + NAMES + iconv.h + PATHS + /opt/gnome/include + /opt/local/include + /opt/local/include + /sw/include + /sw/include + /usr/local/include + /usr/include + PATH_SUFFIXES + glib-2.0 + ) + + FIND_LIBRARY(LIBICONV_LIBRARY + NAMES + iconv + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + + IF (LIBINTL_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBINTL_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBINTL_INCLUDE_DIR}) + ENDIF (LIBINTL_FOUND) + + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) + + ENDIF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + ## + + IF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + SET (GLIB2_FOUND TRUE) + ENDIF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + + IF (GLIB2_FOUND) + IF (NOT GLIB2_FIND_QUIETLY) + MESSAGE (STATUS "Found GLib2: ${GLIB2_LIBRARIES} ${GLIB2_INCLUDE_DIRS}") + ENDIF (NOT GLIB2_FIND_QUIETLY) + ELSE (GLIB2_FOUND) + IF (GLIB2_FIND_REQUIRED) + MESSAGE (SEND_ERROR "Could not find GLib2") + ENDIF (GLIB2_FIND_REQUIRED) + ENDIF (GLIB2_FOUND) + + # show the GLIB2_INCLUDE_DIRS and GLIB2_LIBRARIES variables only in the advanced view + MARK_AS_ADVANCED(GLIB2_INCLUDE_DIRS GLIB2_LIBRARIES) + MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARY) + MARK_AS_ADVANCED(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARY) + +ENDIF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS) + +IF ( WIN32 ) + # include libiconv for win32 + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h PATH_SUFFIXES glib-2.0) + + FIND_LIBRARY(LIBICONV_LIBRARY NAMES iconv) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) +ENDIF ( WIN32 ) + +IF ( GLIB2_FOUND ) + # Check if system has a newer version of glib + # which supports g_regex_match_simple + INCLUDE( CheckIncludeFiles ) + SET( CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS} ) + CHECK_INCLUDE_FILES ( glib/gregex.h HAVE_GLIB_GREGEX_H ) + CHECK_INCLUDE_FILES ( glib/gchecksum.h HAVE_GLIB_GCHECKSUM_H ) + # Reset CMAKE_REQUIRED_INCLUDES + SET( CMAKE_REQUIRED_INCLUDES "" ) +ENDIF( GLIB2_FOUND ) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindWireshark.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindWireshark.cmake new file mode 100644 index 0000000..16fabed --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/FindWireshark.cmake @@ -0,0 +1,28 @@ +# +# Try to find the wireshark library and its includes +# +# This snippet sets the following variables: +# WIRESHARK_FOUND True if wireshark library got found +# WIRESHARK_INCLUDE_DIRS Location of the wireshark headers +# WIRESHARK_LIBRARIES List of libraries to use wireshark +# +# Copyright (c) 2011 Reinhold Kainhofer +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# wireshark does not install its library with pkg-config information, +# so we need to manually find the libraries and headers + +FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/packet.h PATH_SUFFIXES wireshark ) +FIND_LIBRARY( WIRESHARK_LIBRARIES wireshark ) + +# Report results +IF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + SET( WIRESHARK_FOUND 1 ) +ELSE ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + MESSAGE( SEND_ERROR "Could NOT find the wireshark library and headers" ) +ENDIF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/UseMakeDissectorReg.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/UseMakeDissectorReg.cmake new file mode 100644 index 0000000..e7e1a73 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/cmake/UseMakeDissectorReg.cmake @@ -0,0 +1,33 @@ +# +# $Id: UseMakeDissectorReg.cmake 33616 2010-07-22 12:18:36Z stig $ +# +MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype ) + # FIXME: Only the Python stuff has been implemented + # Make this into a MACRO, to avoid duplication with plugins/.../ + #register.c: $(plugin_src) $(ALL_DISSECTORS_SRC) $(top_srcdir)/tools/make-dissector-reg \ + # $(top_srcdir)/tools/make-dissector-reg.py + # @if test -n "$(PYTHON)"; then \ + # echo Making register.c with python ; \ + # $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + # dissectors $(ALL_DISSECTORS_SRC) ; \ + # else \ + # echo Making register.c with shell script ; \ + # $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + # dissectors $(plugin_src) $(ALL_DISSECTORS_SRC) ; \ + # fi + set( _sources ${ARGN} ) + ADD_CUSTOM_COMMAND( + OUTPUT + ${_outputfile} + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ${CMAKE_CURRENT_SOURCE_DIR} + ${_registertype} + ${_sources} + DEPENDS + ${_sources} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ) +ENDMACRO(REGISTER_DISSECTOR_FILES) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.h b/libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.h new file mode 100644 index 0000000..7dfa9cd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.h @@ -0,0 +1,17 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "btle" + + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "0.0.1" + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.nmake b/libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.nmake new file mode 100644 index 0000000..d67b402 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/moduleinfo.nmake @@ -0,0 +1,28 @@ +# +# $Id: moduleinfo.nmake 20155 2006-12-19 22:22:34Z jake $ +# + +# The name +PACKAGE=btle + +# The version +MODULE_VERSION_MAJOR=0 +MODULE_VERSION_MINOR=0 +MODULE_VERSION_MICRO=0 +MODULE_VERSION_EXTRA=1 + +# +# The RC_VERSION should be comma-separated, not dot-separated, +# as per Graham Bloice's message in +# +# http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html +# +# "The RC_VERSION variable in config.nmake should be comma separated. +# This allows the resources to be built correctly and the version +# number to be correctly displayed in the explorer properties dialog +# for the executables, and XP's tooltip, rather than 0.0.0.0." +# + +MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA) +RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/packet-btle.c b/libbtbb-2015-10-R1/wireshark/plugins/btle/packet-btle.c new file mode 100644 index 0000000..d215ac5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/packet-btle.c @@ -0,0 +1,665 @@ +/* packet-btle.c + * Routines for Bluetooth Low Energy dissection + * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* needed for epan/gcc-4.x */ +#include +#include + +/* function prototypes */ +void proto_reg_handoff_btle(void); + +/* initialize the protocol and registered fields */ +static int proto_btle = -1; +static int hf_btle_pkthdr = -1; +static int hf_btle_aa = -1; +static int hf_btle_type = -1; +static int hf_btle_randomized_tx = -1; +static int hf_btle_randomized_rx = -1; +static int hf_btle_length = -1; +static int hf_btle_adv_addr = -1; +static int hf_btle_adv_data = -1; +static int hf_btle_init_addr = -1; +static int hf_btle_scan_addr = -1; +static int hf_btle_scan_rsp_data = -1; +static int hf_btle_connect = -1; +static int hf_btle_connect_aa = -1; +static int hf_btle_crc_init = -1; +static int hf_btle_win_size = -1; +static int hf_btle_win_offset = -1; +static int hf_btle_interval = -1; +static int hf_btle_latency = -1; +static int hf_btle_timeout = -1; +static int hf_btle_data = -1; +static int hf_btle_data_llid = -1; +static int hf_btle_data_nesn = -1; +static int hf_btle_data_sn = -1; +static int hf_btle_data_md = -1; +static int hf_btle_data_rfu = -1; +static int hf_btle_ll_control_opcode = -1; +static int hf_btle_ll_control_data = -1; +static int hf_btle_ll_control_ll_enc_req = -1; +static int hf_btle_ll_control_ll_enc_req_rand = -1; +static int hf_btle_ll_control_ll_enc_req_ediv = -1; +static int hf_btle_ll_control_ll_enc_req_skdm = -1; +static int hf_btle_ll_control_ll_enc_req_ivm = -1; +static int hf_btle_ll_control_ll_enc_rsp = -1; +static int hf_btle_ll_control_ll_enc_rsp_skds = -1; +static int hf_btle_ll_control_ll_enc_rsp_ivs = -1; +static int hf_btle_crc = -1; + +static const value_string packet_types[] = { + { 0x0, "ADV_IND" }, + { 0x1, "ADV_DIRECT_IND" }, + { 0x2, "ADV_NONCONN_IND" }, + { 0x3, "SCAN_REQ" }, + { 0x4, "SCAN_RSP" }, + { 0x5, "CONNECT_REQ" }, + { 0x6, "ADV_SCAN_IND" }, + { 0, NULL } +}; + +static const value_string llid_codes[] = { + { 0x0, "undefined" }, + { 0x1, "Continuation fragment of an L2CAP message" }, + { 0x2, "Start of an L2CAP message or no fragmentation" }, + { 0x3, "LL Control PDU" }, + { 0, NULL } +}; + +static const value_string ll_control_opcodes[] = { + { 0x00, "LL_CONNECTION_UPDATE_REQ" }, + { 0x01, "LL_CHANNEL_MAP_REQ" }, + { 0x02, "LL_TERMINATE_IND" }, + { 0x03, "LL_ENC_REQ" }, + { 0x04, "LL_ENC_RSP" }, + { 0x05, "LL_START_ENC_REQ" }, + { 0x06, "LL_START_ENC_RSP" }, + { 0x07, "LL_UNKNOWN_RSP" }, + { 0x08, "LL_FEATURE_REQ" }, + { 0x09, "LL_FEATURE_RSP" }, + { 0x0A, "LL_PAUSE_ENC_REQ" }, + { 0x0B, "LL_PAUSE_ENC_RSP" }, + { 0x0C, "LL_VERSION_IND" }, + { 0x0D, "LL_REJECT_IND" }, + { 0, NULL } +}; + +static const guint32 ADV_AA = 0x8e89bed6; + +/* initialize the subtree pointers */ +static gint ett_btle = -1; +static gint ett_btle_pkthdr = -1; +static gint ett_btle_connect = -1; +static gint ett_btle_data = -1; +static gint ett_ll_enc_req = -1; +static gint ett_ll_enc_rsp = -1; + +/* subdissectors */ +static dissector_handle_t btl2cap_handle = NULL; + +void +dissect_adv_ind_or_nonconn_or_scan(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int datalen) +{ + const guint8 *adv_addr; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + adv_addr = tvb_get_ptr(tvb, offset, 6); + SET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr); + + proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr); + proto_tree_add_item(tree, hf_btle_adv_data, tvb, offset + 6, datalen, TRUE); +} + +void +dissect_adv_direct_ind(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) +{ + const guint8 *adv_addr, *init_addr; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + adv_addr = tvb_get_ptr(tvb, offset, 6); + SET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr); + init_addr = tvb_get_ptr(tvb, offset+6, 6); + SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, init_addr); + + proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr); + proto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset + 6, 6, init_addr); +} + +void +dissect_scan_req(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) +{ + const guint8 *scan_addr, *adv_addr; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + scan_addr = tvb_get_ptr(tvb, offset, 6); + SET_ADDRESS(&pinfo->src, AT_ETHER, 6, scan_addr); + adv_addr = tvb_get_ptr(tvb, offset+6, 6); + SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, adv_addr); + + proto_tree_add_ether(tree, hf_btle_scan_addr, tvb, offset, 6, scan_addr); + proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset+6, 6, adv_addr); +} + +void +dissect_scan_rsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int datalen) +{ + const guint8 *adv_addr; + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + adv_addr = tvb_get_ptr(tvb, offset, 6); + SET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr); + + proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr); + proto_tree_add_item(tree, hf_btle_scan_rsp_data, tvb, offset + 6, datalen, TRUE); +} + +void +dissect_connect_req(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset) +{ + proto_item *connect_item; + proto_tree *connect_tree; + const guint8 *adv_addr, *init_addr; + + + DISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1); + + init_addr = tvb_get_ptr(tvb, offset, 6); + SET_ADDRESS(&pinfo->src, AT_ETHER, 6, init_addr); + adv_addr = tvb_get_ptr(tvb, offset+6, 6); + SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, adv_addr); + + proto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset, 6, init_addr); + proto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset + 6, 6, adv_addr); + offset += 12; + + connect_item = proto_tree_add_item(tree, hf_btle_connect, tvb, offset, 22, TRUE); + connect_tree = proto_item_add_subtree(connect_item, ett_btle_connect); + + proto_tree_add_item(connect_tree, hf_btle_connect_aa, tvb, offset+ 0, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(connect_tree, hf_btle_crc_init, tvb, offset+ 4, 3, ENC_LITTLE_ENDIAN); + proto_tree_add_item(connect_tree, hf_btle_win_size, tvb, offset+ 7, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(connect_tree, hf_btle_win_offset, tvb, offset+ 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(connect_tree, hf_btle_interval, tvb, offset+10, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(connect_tree, hf_btle_latency, tvb, offset+12, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(connect_tree, hf_btle_timeout, tvb, offset+14, 2, ENC_LITTLE_ENDIAN); +} + +void +dissect_ll_enc_req(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_item *ll_enc_req_item; + proto_tree *ll_enc_req_tree; + + ll_enc_req_item = proto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req, tvb, offset + 1, 22, TRUE); + ll_enc_req_tree = proto_item_add_subtree(ll_enc_req_item, ett_ll_enc_req); + + proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_rand, tvb, offset + 1, 8, TRUE); + proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_ediv, tvb, offset + 9, 2, TRUE); + proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_skdm, tvb, offset + 11, 8, TRUE); + proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_ivm, tvb, offset + 19, 4, TRUE); +} + +void +dissect_ll_enc_rsp(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_item *ll_enc_rsp_item; + proto_tree *ll_enc_rsp_tree; + + ll_enc_rsp_item = proto_tree_add_item(tree, hf_btle_ll_control_ll_enc_rsp, tvb, offset + 1, 12, TRUE); + ll_enc_rsp_tree = proto_item_add_subtree(ll_enc_rsp_item, ett_ll_enc_rsp); + + proto_tree_add_item(ll_enc_rsp_tree, hf_btle_ll_control_ll_enc_rsp_skds, tvb, offset + 1, 8, TRUE); + proto_tree_add_item(ll_enc_rsp_tree, hf_btle_ll_control_ll_enc_rsp_ivs, tvb, offset + 9, 4, TRUE); +} + +void +dissect_ll_control(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, guint8 length) +{ + guint8 ll_control_opcode; + + proto_tree_add_item(tree, hf_btle_ll_control_opcode, tvb, offset, 1, ENC_NA); + + ll_control_opcode = tvb_get_guint8(tvb, offset); + if (ll_control_opcode <= 0x0d) { + col_add_fstr(pinfo->cinfo, COL_INFO, "LL Control PDU: %s", + ll_control_opcodes[ll_control_opcode].strptr); + + switch (ll_control_opcode) { + case 0x03: // LL_ENC_REQ + dissect_ll_enc_req(tree, tvb, offset); + break; + case 0x04: // LL_ENC_RSP + dissect_ll_enc_rsp(tree, tvb, offset); + break; + default: + if (length > 1) + proto_tree_add_item(tree, hf_btle_ll_control_data, tvb, offset + 1, length-1, TRUE); + break; + } + } else { + col_set_str(pinfo->cinfo, COL_INFO, "LL Control PDU: unknown"); + if (length > 1) + proto_tree_add_item(tree, hf_btle_ll_control_data, tvb, offset + 1, length-1, TRUE); + } +} + +/* dissect a packet */ +static void +dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *btle_item, *pkthdr_item, *data_item; + proto_tree *btle_tree, *pkthdr_tree, *data_tree; + int offset; + guint32 aa; + guint8 type, length; + guint8 llid; + tvbuff_t *pld_tvb; + + /* + * FIXME + * I have no idea what this does, but the L2CAP dissector segfaults + * without it. + */ + guint16 fake_acl_data; + +#if 0 + /* sanity check: length */ + if (tvb_length(tvb) > 0 && tvb_length(tvb) < 9) + /* bad length: look for a different dissector */ + return 0; +#endif + + /* make entries in protocol column and info column on summary display */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bluetooth LE"); + + aa = tvb_get_letohl(tvb, 0); + + // advertising packet + if (aa == ADV_AA) { + type = tvb_get_guint8(tvb, 4) & 0xf; + length = tvb_get_guint8(tvb, 5) & 0x3f; + + /* see if we are being asked for details */ + if (tree) { + + /* create display subtree for the protocol */ + offset = 0; + btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, TRUE); + btle_tree = proto_item_add_subtree(btle_item, ett_btle); + + proto_tree_add_item(btle_tree, hf_btle_aa, tvb, offset, 4, TRUE); + offset += 4; + + /* packet header */ + pkthdr_item = proto_tree_add_item(btle_tree, hf_btle_pkthdr, tvb, offset, 2, ENC_LITTLE_ENDIAN); + pkthdr_tree = proto_item_add_subtree(pkthdr_item, ett_btle_pkthdr); + + proto_tree_add_bits_item(pkthdr_tree, hf_btle_randomized_rx, tvb, offset * 8, 1, TRUE); + proto_tree_add_bits_item(pkthdr_tree, hf_btle_randomized_tx, tvb, offset * 8 + 1, 1, TRUE); + proto_tree_add_bits_item(pkthdr_tree, hf_btle_type, tvb, offset * 8 + 4, 4, TRUE); + offset += 1; + + proto_tree_add_item(pkthdr_tree, hf_btle_length, tvb, offset, 1, TRUE); + offset += 1; + + if (check_col(pinfo->cinfo, COL_INFO)) { + if (type <= 0x6) { + col_set_str(pinfo->cinfo, COL_INFO, packet_types[type].strptr); + } else { + col_set_str(pinfo->cinfo, COL_INFO, "Unknown"); + } + } + + /* payload */ + switch (type) { + case 0x0: // ADV_IND + case 0x2: // ADV_NONCONN_IND + case 0x6: // ADV_SCAN_IND + dissect_adv_ind_or_nonconn_or_scan(btle_tree, tvb, pinfo, offset, length - 6); + break; + case 0x1: // ADV_DIRECT_IND + dissect_adv_direct_ind(btle_tree, tvb, pinfo, offset); + break; + case 0x3: + dissect_scan_req(btle_tree, tvb, pinfo, offset); + break; + case 0x4: // SCAN_RSP + dissect_scan_rsp(btle_tree, tvb, pinfo, offset, length - 6); + break; + case 0x5: // CONNECT_REQ + dissect_connect_req(btle_tree, tvb, pinfo, offset); + break; + default: + break; + } + + offset += length; + proto_tree_add_item(btle_tree, hf_btle_crc, tvb, offset, 3, TRUE); + } + } + + // data PDU + else { + if (tree) { + col_set_str(pinfo->cinfo, COL_INFO, "Data"); + + length = tvb_get_guint8(tvb, 5) & 0x1f; + + /* create display subtree for the protocol */ + offset = 0; + btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, TRUE); + btle_tree = proto_item_add_subtree(btle_item, ett_btle); + + proto_tree_add_item(btle_tree, hf_btle_aa, tvb, offset, 4, TRUE); + offset += 4; + + // data PDU header + data_item = proto_tree_add_item(btle_tree, hf_btle_data, tvb, offset, 2, TRUE); + data_tree = proto_item_add_subtree(data_item, ett_btle_data); + + proto_tree_add_item(data_tree, hf_btle_data_rfu, tvb, offset, 1, ENC_NA); + proto_tree_add_item(data_tree, hf_btle_data_md, tvb, offset, 1, ENC_NA); + proto_tree_add_item(data_tree, hf_btle_data_sn, tvb, offset, 1, ENC_NA); + proto_tree_add_item(data_tree, hf_btle_data_nesn, tvb, offset, 1, ENC_NA); + proto_tree_add_item(data_tree, hf_btle_data_llid, tvb, offset, 1, ENC_NA); + llid = tvb_get_guint8(tvb, offset) & 0x3; + offset += 1; + + proto_tree_add_item(data_tree, hf_btle_length, tvb, offset, 1, TRUE); + offset += 1; + + // LL control PDU + if (llid == 0x3) { + dissect_ll_control(btle_tree, tvb, pinfo, offset, length); + } + + // L2CAP + else if (llid == 0x1 || llid == 0x2) { + if (length > 0 && btl2cap_handle) { + pinfo->private_data = &fake_acl_data; + pld_tvb = tvb_new_subset(tvb, offset, length, length); + call_dissector(btl2cap_handle, pld_tvb, pinfo, btle_tree); + } + else if (length == 0) { + col_set_str(pinfo->cinfo, COL_INFO, "Empty Data PDU"); + } + } + + offset += length; + + proto_tree_add_item(btle_tree, hf_btle_crc, tvb, offset, 3, TRUE); + } + } + + return; +} + +/* register the protocol with Wireshark */ +void +proto_register_btle(void) +{ + + /* list of fields */ + static hf_register_info hf[] = { + { &hf_btle_aa, + { "Access Address", "btle.aa", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_btle_pkthdr, + { "Packet Header", "btle.pkthdr", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_btle_type, + { "TYPE", "btle.type", + FT_UINT8, BASE_HEX, VALS(packet_types), 0x0, + "Packet Type", HFILL } + }, + { &hf_btle_randomized_tx, + { "Randomized TX Address", "btle.randomized_tx", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, + NULL, HFILL } + }, + { &hf_btle_randomized_rx, + { "Randomized RX Address", "btle.randomized_rx", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, + NULL, HFILL } + }, + { &hf_btle_length, + { "Length", "btle.length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_adv_addr, + { "Advertising Address", "btle.adv_addr", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_init_addr, + { "Init Address", "btle.init_addr", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_scan_addr, + { "Scan Address", "btle.scan_addr", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_adv_data, + { "Advertising Data", "btle.adv_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_scan_rsp_data, + { "Scan Response Data", "btle.scan_rsp_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + // connection packet fields + { &hf_btle_connect, + { "Connection Request", "btle.connect", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_connect_aa, + { "Connection AA", "btle.connect.aa", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_crc_init, + { "CRC Init", "btle.connect.crc_init", + FT_UINT24, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_win_size, + { "Window Size", "btle.connect.win_size", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_win_offset, + { "Window Offset", "btle.connect.win_offset", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_interval, + { "Interval", "btle.connect.interval", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_latency, + { "Latency", "btle.connect.latency", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_timeout, + { "Timeout", "btle.connect.timeout", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + + // data header + { &hf_btle_data, + { "Data PDU Header", "btle.data", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_data_llid, + { "LLID", "btle.data.llid", + FT_UINT8, BASE_DEC, VALS(llid_codes), 0x3, + NULL, HFILL } + }, + { &hf_btle_data_nesn, + { "NESN", "btle.data.nesn", + FT_UINT8, BASE_DEC, NULL, 0x4, + "Next Expected Sequence Number", HFILL } + }, + { &hf_btle_data_sn, + { "SN", "btle.data.sn", + FT_UINT8, BASE_DEC, NULL, 0x8, + "Sequence Number", HFILL } + }, + { &hf_btle_data_md, + { "MD", "btle.data.md", + FT_UINT8, BASE_DEC, NULL, 0x10, + "More Data", HFILL } + }, + { &hf_btle_data_rfu, + { "RFU", "btle.data.rfu", + FT_UINT8, BASE_DEC, NULL, 0xe0, + "Reserved for Future Use (must be zero)", HFILL } + }, + + { &hf_btle_ll_control_opcode, + { "LL Control Opcode", "btle.ll_control_opcode", + FT_UINT8, BASE_HEX, VALS(ll_control_opcodes), 0x0, + NULL, HFILL } + }, + { &hf_btle_ll_control_data, + { "LL Control Data", "btle.ll_control_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_btle_ll_control_ll_enc_req, + { "Encryption Request", "btle.ll_enc_req", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_ll_control_ll_enc_req_rand, + { "Rand", "btle.ll_enc_req.rand", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_ll_control_ll_enc_req_ediv, + { "EDIV", "btle.ll_enc_req.ediv", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Encrypted Diversifier", HFILL } + }, + { &hf_btle_ll_control_ll_enc_req_skdm, + { "SDKm", "btle.ll_enc_req.skdm", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Master's Session Key Identifier", HFILL } + }, + { &hf_btle_ll_control_ll_enc_req_ivm, + { "IVm", "btle.ll_enc_req.ivm", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Master's Initialization Vector", HFILL } + }, + + { &hf_btle_ll_control_ll_enc_rsp, + { "Encryption Response", "btle.ll_enc_rsp", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_ll_control_ll_enc_rsp_skds, + { "SDKs", "btle.ll_enc_rsp.skds", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Slave's Session Key Identifier", HFILL } + }, + { &hf_btle_ll_control_ll_enc_rsp_ivs, + { "IVs", "btle.ll_enc_rsp.ivs", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Slave's Initialization Vector", HFILL } + }, + + + { &hf_btle_crc, + { "CRC", "btle.crc", + FT_UINT24, BASE_HEX, NULL, 0x0, + "Ticklish Redundancy Check", HFILL } + }, + }; + + /* protocol subtree arrays */ + static gint *ett[] = { + &ett_btle, + &ett_btle_pkthdr, + &ett_btle_connect, + &ett_btle_data, + &ett_ll_enc_req, + &ett_ll_enc_rsp, + }; + + /* register the protocol name and description */ + proto_btle = proto_register_protocol( + "Bluetooth Low Energy", /* full name */ + "BTLE", /* short name */ + "btle" /* abbreviation (e.g. for filters) */ + ); + + register_dissector("btle", dissect_btle, proto_btle); + + /* register the header fields and subtrees used */ + proto_register_field_array(proto_btle, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_reg_handoff_btle(void) +{ + static gboolean inited = FALSE; + + if (!inited) { + dissector_handle_t btle_handle; + + // btle_handle = new_create_dissector_handle(dissect_btle, proto_btle); + // dissector_add("ppi.dlt", 147, btle_handle); + + btl2cap_handle = find_dissector("btl2cap"); + + inited = TRUE; + } +} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/plugin.rc.in b/libbtbb-2015-10-R1/wireshark/plugins/btle/plugin.rc.in new file mode 100644 index 0000000..568dc07 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/plugin.rc.in @@ -0,0 +1,34 @@ +#include "winver.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @RC_MODULE_VERSION@ + PRODUCTVERSION @RC_VERSION@ + FILEFLAGSMASK 0x0L +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0" + VALUE "FileDescription", "@PACKAGE@ dissector\0" + VALUE "FileVersion", "@MODULE_VERSION@\0" + VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0" + VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs , Gilbert Ramirez and others\0" + VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0" + VALUE "ProductName", "Wireshark\0" + VALUE "ProductVersion", "@VERSION@\0" + VALUE "Comments", "Build with @MSVC_VARIANT@\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg b/libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg new file mode 100755 index 0000000..d2efa7c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg.py b/libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg.py new file mode 100755 index 0000000..060460c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/tools/make-dissector-reg.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $ + +import os +import sys +import re +import pickle +from stat import * + +VERSION_KEY = '_VERSION' +CUR_VERSION = '$Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $' + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin" or registertype == "plugin_wtap": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by Makefile or Makefile.nmake. + */ +""" +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by the "register.c" target in + * epan/dissectors/Makefile or Makefile.nmake using information in + * epan/dissectors/register-cache.pkl. + * + * You can force this file to be regenerated completely by deleting + * it along with epan/dissectors/register-cache.pkl. + */ +""" +else: + print(("Unknown output type '%s'" % registertype)) + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append(os.path.join(srcdir, file)) + +if len(filenames) < 1: + print("No files found") + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +wtap_reg_regex0 = r"^(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" +wtap_reg_regex1 = r"void\s+(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ( 'wtap_register', re.compile(wtap_reg_regex0) ), + ( 'wtap_register', re.compile(wtap_reg_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION: + cache = {VERSION_KEY: CUR_VERSION} + except: + cache = {VERSION_KEY: CUR_VERSION} + + print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1))) + +# Grep +cache_hits = 0 +cache_misses = 0 +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and filename in cache: + cdict = cache[filename] + if cur_mtime == cdict['mtime']: + cache_hits += 1 +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + regs['wtap_register'].extend(cdict['wtap_register']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache_misses += 1 + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses))) + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print("No protocol registrations found") + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() +regs['wtap_register'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write(preamble) + +# Make the routine to register all protocols +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +elif registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +register_wtap_module(void) +{ +"""); + + for symbol in regs['wtap_register']: + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + reg_code.write(line) + + reg_code.write("}\n"); + reg_code.write("#endif\n"); +else: + reg_code.write(""" +static gulong proto_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['proto_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +static gulong handoff_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['handoff_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return proto_reg_count() + handoff_reg_count();" + reg_code.write(line) + + reg_code.write(""" +}\n +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btle/wireshark-1.8-btle-ppi.patch b/libbtbb-2015-10-R1/wireshark/plugins/btle/wireshark-1.8-btle-ppi.patch new file mode 100644 index 0000000..9953779 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btle/wireshark-1.8-btle-ppi.patch @@ -0,0 +1,246 @@ +Index: wireshark-1.8.2/epan/dissectors/packet-ppi.c +=================================================================== +--- wireshark-1.8.2.orig/epan/dissectors/packet-ppi.c 2013-02-01 12:18:18.208820553 -0800 ++++ wireshark-1.8.2/epan/dissectors/packet-ppi.c 2013-02-01 12:18:50.000000000 -0800 +@@ -181,6 +181,7 @@ + PPI_VECTOR_INFO = 30003, /* currently available in draft from. jellch@harris.com */ + PPI_SENSOR_INFO = 30004, + PPI_ANTENNA_INFO = 30005, ++ PPI_BTLE = 30006, + CACE_PRIVATE = 0xCACE + /* All others RESERVED. Contact the WinPcap team for an assignment */ + } ppi_field_type; +@@ -319,7 +320,7 @@ + + static dissector_handle_t data_handle; + static dissector_handle_t ieee80211_ht_handle; +-static dissector_handle_t ppi_gps_handle, ppi_vector_handle, ppi_sensor_handle, ppi_antenna_handle; ++static dissector_handle_t ppi_gps_handle, ppi_vector_handle, ppi_sensor_handle, ppi_antenna_handle, ppi_btle_handle; + + + static const true_false_string tfs_ppi_head_flag_alignment = { "32-bit aligned", "Not aligned" }; +@@ -881,7 +882,19 @@ + call_dissector(ppi_antenna_handle, next_tvb, pinfo, ppi_tree); + } + break; +- ++ case PPI_BTLE: ++ if (ppi_btle_handle == NULL) ++ { ++ proto_tree_add_text(ppi_tree, tvb, offset, data_len, ++ "%s (%u bytes)", val_to_str(data_type, (value_string *)&vs_ppi_field_type, "BTLE: "), data_len); ++ } ++ else /* we found a suitable dissector */ ++ { ++ /* skip over the ppi_fieldheader, and pass it off to the dedicated BTLE dissetor */ ++ next_tvb = tvb_new_subset(tvb, offset + 4, data_len - 4 , -1); ++ call_dissector(ppi_btle_handle, next_tvb, pinfo, ppi_tree); ++ } ++ break; + default: + if (tree) + proto_tree_add_text(ppi_tree, tvb, offset, data_len, +@@ -1365,6 +1378,7 @@ + ppi_vector_handle = find_dissector("ppi_vector"); + ppi_sensor_handle = find_dissector("ppi_sensor"); + ppi_antenna_handle = find_dissector("ppi_antenna"); ++ ppi_btle_handle = find_dissector("ppi_btle"); + + dissector_add_uint("wtap_encap", WTAP_ENCAP_PPI, ppi_handle); + } +Index: wireshark-1.8.2/epan/dissectors/packet-ppi-btle.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ wireshark-1.8.2/epan/dissectors/packet-ppi-btle.c 2013-02-01 13:37:09.020642835 -0800 +@@ -0,0 +1,179 @@ ++/* packet-ppi-btle.c ++ * Routines for PPI-BTLE dissection ++ * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com ++ * ++ * $Id$ ++ * ++ * Wireshark - Network traffic analyzer ++ * By Gerald Combs ++ * Copyright 1998 Gerald Combs ++ * ++ * Copied from packet-ppi-gps.c ++ * ++ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++#include ++ ++#define PPI_BTLE_MINTAGLEN 12 ++#define PPI_BTLE_MAXTAGLEN 12 ++ ++/* protocol */ ++static int proto_ppi_btle = -1; ++ ++static int hf_ppi_btle_version = -1; ++static int hf_ppi_btle_channel = -1; ++static int hf_ppi_btle_clkn_high = -1; ++static int hf_ppi_btle_clk100ns = -1; ++static int hf_ppi_btle_rssi_max = -1; ++static int hf_ppi_btle_rssi_min = -1; ++static int hf_ppi_btle_rssi_avg = -1; ++static int hf_ppi_btle_rssi_count = -1; ++ ++static gint ett_ppi_btle = -1; ++ ++static void ++dissect_ppi_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { ++ /* These are locals used for processing the current tvb */ ++ guint length; ++ guint version; ++ guint32 channel, clkn_high, clk100ns; ++ guint8 urssi_max, urssi_min, urssi_avg; ++ gint8 rssi_max, rssi_min, rssi_avg; ++ guint rssi_count; ++ ++ proto_tree *ppi_btle_tree = NULL; ++ proto_tree *pt, *present_tree = NULL; ++ ++ proto_item *ti = NULL; ++ ++ /* Clear out stuff in the info column */ ++ col_clear(pinfo->cinfo,COL_INFO); ++ ++ /* Setup basic column info */ ++ if (check_col(pinfo->cinfo, COL_INFO)) ++ col_add_fstr(pinfo->cinfo, COL_INFO, "PPI_BTLE Capture"); ++ ++ /* Create the basic dissection tree*/ ++ if (tree) ++ ti = proto_tree_add_protocol_format(tree, proto_ppi_btle, tvb, 0, length, "BTLE:"); ++ ++ /* Sanity check length of tag */ ++ length = tvb_length(tvb); ++ if (length < PPI_BTLE_MINTAGLEN) { ++ if (tree) ++ proto_item_append_text(ti, "Invalid PPI-BTLE length (got %d, %d min)", length, PPI_BTLE_MAXTAGLEN); ++ return; ++ } ++ ++ if (tree) { ++ channel = tvb_get_letohs(tvb, 1); ++ clkn_high = tvb_get_guint8(tvb, 3); ++ clk100ns = tvb_get_letohl(tvb, 4); ++ urssi_max = tvb_get_guint8(tvb, 8); ++ urssi_min = tvb_get_guint8(tvb, 9); ++ urssi_avg = tvb_get_guint8(tvb, 10); ++ rssi_count = tvb_get_guint8(tvb, 11); ++ ++ rssi_max = *(gint8 *)&urssi_max; ++ rssi_min = *(gint8 *)&urssi_min; ++ rssi_avg = *(gint8 *)&urssi_avg; ++ ++ ppi_btle_tree= proto_item_add_subtree(ti, ett_ppi_btle); ++ proto_tree_add_uint(ppi_btle_tree, hf_ppi_btle_version, tvb, 0, 1, version); ++ proto_tree_add_uint(ppi_btle_tree, hf_ppi_btle_channel, tvb, 1, 2, channel); ++ proto_tree_add_uint(ppi_btle_tree, hf_ppi_btle_clkn_high, tvb, 3, 1, clkn_high); ++ proto_tree_add_uint(ppi_btle_tree, hf_ppi_btle_clk100ns, tvb, 4, 4, clk100ns); ++ proto_tree_add_int(ppi_btle_tree, hf_ppi_btle_rssi_max, tvb, 8, 1, rssi_max); ++ proto_tree_add_int(ppi_btle_tree, hf_ppi_btle_rssi_min, tvb, 9, 1, rssi_min); ++ proto_tree_add_int(ppi_btle_tree, hf_ppi_btle_rssi_avg, tvb, 10, 1, rssi_avg); ++ proto_tree_add_uint(ppi_btle_tree, hf_ppi_btle_rssi_count, tvb, 11, 1, rssi_count); ++ } ++ ++ version = tvb_get_guint8(tvb, 0); ++ if (version > 0) { ++ if (tree) ++ proto_item_append_text(ti, "Warning: New version of PPI-BTLE (length %d, I can only decode first %d bytes)", length, PPI_BTLE_MAXTAGLEN); ++ } ++ ++ /* perform tag-specific max length sanity checking */ ++ else if (length > PPI_BTLE_MAXTAGLEN ) { ++ if (tree) ++ proto_item_append_text(ti, "Invalid PPI-BTLE length (got %d, %d max)", length, PPI_BTLE_MAXTAGLEN); ++ return; ++ } ++ ++ return; ++} ++ ++void ++proto_register_ppi_btle(void) { ++ /* The following array initializes those header fields declared above to the values displayed */ ++ static hf_register_info hf[] = { ++ ++ { &hf_ppi_btle_version, ++ { "Version", "ppi_btle.version", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } }, ++ ++ { &hf_ppi_btle_channel, ++ { "Channel", "ppi_btle.channel", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "MHz", HFILL } }, ++ ++ { &hf_ppi_btle_clkn_high, ++ { "clkn_high", "ppi_btle.clkn_high", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "High bits of native clock", HFILL } }, ++ ++ { &hf_ppi_btle_clk100ns, ++ { "clk100ns", "ppi_btle.clk100ns", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "100 ns clock", HFILL } }, ++ ++ // RSSI ++ { &hf_ppi_btle_rssi_max, ++ { "Max RSSI", "ppi_btle.rssi_max", ++ FT_INT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } }, ++ { &hf_ppi_btle_rssi_min, ++ { "Min RSSI", "ppi_btle.rssi_min", ++ FT_INT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } }, ++ { &hf_ppi_btle_rssi_avg, ++ { "Average RSSI", "ppi_btle.rssi_avg", ++ FT_INT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } }, ++ { &hf_ppi_btle_rssi_count, ++ { "RSSI Count", "ppi_btle.rssi_count", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } }, ++ ++ }; ++ ++ static gint *ett[] = { ++ &ett_ppi_btle, ++ }; ++ ++ proto_ppi_btle = proto_register_protocol("PPI Ubertooth BTLE tag decoder", "PPI BTLE Decoder", "ppi_btle"); ++ proto_register_field_array(proto_ppi_btle, hf, array_length(hf)); ++ proto_register_subtree_array(ett, array_length(ett)); ++ register_dissector("ppi_btle", dissect_ppi_btle, proto_ppi_btle); ++} +Index: wireshark-1.8.2/epan/dissectors/Makefile.common +=================================================================== +--- wireshark-1.8.2.orig/epan/dissectors/Makefile.common 2013-01-29 11:46:35.429559060 -0800 ++++ wireshark-1.8.2/epan/dissectors/Makefile.common 2013-01-29 11:56:46.541536579 -0800 +@@ -881,6 +881,7 @@ + packet-ppi-gps.c \ + packet-ppi-sensor.c \ + packet-ppi-vector.c \ ++ packet-ppi-btle.c \ + packet-ppp.c \ + packet-pppoe.c \ + packet-pptp.c \ diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/AUTHORS b/libbtbb-2015-10-R1/wireshark/plugins/btsm/AUTHORS new file mode 100644 index 0000000..7658f97 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/AUTHORS @@ -0,0 +1,3 @@ +Authors: +Mike Ryan +Michael Ossmann diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/CMakeLists.txt b/libbtbb-2015-10-R1/wireshark/plugins/btsm/CMakeLists.txt new file mode 100644 index 0000000..a1b1b81 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/CMakeLists.txt @@ -0,0 +1,88 @@ +# CMakeLists.txt +# +# $Id: CMakeLists.txt 31995 2010-02-24 22:32:10Z jmayer $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +project(btsm-wireshark-plugin C) + +cmake_minimum_required(VERSION 2.6) +set(CMAKE_BACKWARDS_COMPATIBILITY 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +IF ( NOT CMAKE_INSTALL_LIBDIR ) + set(CMAKE_INSTALL_LIBDIR ~/.wireshark/plugins) +ENDIF ( NOT CMAKE_INSTALL_LIBDIR ) +MESSAGE (STATUS "Plugin will be installed in: ${CMAKE_INSTALL_LIBDIR}") + +INCLUDE(UseMakeDissectorReg) + +set(GLIB2_MIN_VERSION 2.4.0) + +find_package(GLIB2) +include_directories (${GLIB2_INCLUDE_DIRS}) + +find_package(Wireshark) +include_directories (${WIRESHARK_INCLUDE_DIRS}) + +set(LINK_MODE_LIB SHARED) +set(LINK_MODE_MODULE MODULE) + + +set(DISSECTOR_SRC + packet-btsm.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} +) + +set(CLEAN_FILES + ${PLUGIN_FILES} +) + +if (WERROR) + set_source_files_properties( + ${CLEAN_FILES} + PROPERTIES + COMPILE_FLAGS -Werror + ) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +register_dissector_files(plugin.c + plugin + ${DISSECTOR_SRC} +) + +add_library(btsm ${LINK_MODE_MODULE} + ${PLUGIN_FILES} +) +set_target_properties(btsm PROPERTIES PREFIX "") +set_target_properties(btsm PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}") + +target_link_libraries(btsm wireshark) + +install(TARGETS btsm + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/ NAMELINK_SKIP +) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btsm/COPYING new file mode 100644 index 0000000..aa0aea5 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.am b/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.am new file mode 100644 index 0000000..b998689 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.am @@ -0,0 +1,125 @@ +# Makefile.am +# Automake file for AgentX plugin +# +# $Id: Makefile.am 24488 2008-02-27 16:18:30Z stig $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +INCLUDES = -I$(top_srcdir) -I$(includedir) + +include Makefile.common + +#if HAVE_WARNINGS_AS_ERRORS +#AM_CFLAGS = -Werror +#endif + +plugindir = @plugindir@ + +plugin_LTLIBRARIES = btsm.la +btsm_la_SOURCES = \ + plugin.c \ + moduleinfo.h \ + $(DISSECTOR_SRC) \ + $(DISSECTOR_SUPPORT_SRC) \ + $(DISSECTOR_INCLUDES) +btsm_la_LDFLAGS = -module -avoid-version +btsm_la_LIBADD = @PLUGIN_LIBS@ + +# Libs must be cleared, or else libtool won't create a shared module. +# If your module needs to be linked against any particular libraries, +# add them here. +LIBS = + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ + $(top_srcdir)/tools/make-dissector-reg.py + @if test -n "$(PYTHON)"; then \ + echo Making plugin.c with python ; \ + $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + plugin $(DISSECTOR_SRC) ; \ + else \ + echo Making plugin.c with shell script ; \ + $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + $(plugin_src) plugin $(DISSECTOR_SRC) ; \ + fi + +# +# Currently plugin.c can be included in the distribution because +# we always build all protocol dissectors. We used to have to check +# whether or not to build the snmp dissector. If we again need to +# variably build something, making plugin.c non-portable, uncomment +# the dist-hook line below. +# +# Oh, yuk. We don't want to include "plugin.c" in the distribution, as +# its contents depend on the configuration, and therefore we want it +# to be built when the first "make" is done; however, Automake insists +# on putting *all* source into the distribution. +# +# We work around this by having a "dist-hook" rule that deletes +# "plugin.c", so that "dist" won't pick it up. +# +#dist-hook: +# @rm -f $(distdir)/plugin.c + +CLEANFILES = \ + btsm \ + *~ + +MAINTAINERCLEANFILES = \ + Makefile.in \ + plugin.c + +EXTRA_DIST = \ + Makefile.common \ + Makefile.nmake \ + moduleinfo.nmake \ + plugin.rc.in diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.common b/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.common new file mode 100644 index 0000000..6489554 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.common @@ -0,0 +1,39 @@ +# Makefile.common for AgentX plugin +# Contains the stuff from Makefile.am and Makefile.nmake that is +# a) common to both files and +# b) portable between both files +# +# $Id: Makefile.common 23848 2007-12-12 22:10:50Z jake $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# the name of the plugin +PLUGIN_NAME = btsm + +# the dissector sources (without any helpers) +DISSECTOR_SRC = \ + packet-btsm.c + +# corresponding headers +DISSECTOR_INCLUDES = + +# Dissector helpers. They're included in the source files in this +# directory, but they're not dissectors themselves, i.e. they're not +# used to generate "plugin.c". +DISSECTOR_SUPPORT_SRC = diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.nmake b/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.nmake new file mode 100644 index 0000000..857e435 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/Makefile.nmake @@ -0,0 +1,100 @@ +# Makefile.nmake +# nmake file for Wireshark plugin +# +# $Id: Makefile.nmake 24520 2008-03-01 12:31:01Z jake $ +# + +include ..\..\config.nmake +include moduleinfo.nmake + +include Makefile.common + +CFLAGS=/WX /DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \ + /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS) + +.c.obj:: + $(CC) $(CFLAGS) -Fd.\ -c $< + +LDFLAGS = $(PLUGIN_LDFLAGS) + +!IFDEF ENABLE_LIBWIRESHARK +LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib +CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS) + +DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj) + +DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj) + +OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) plugin.obj + +RESOURCE=$(PLUGIN_NAME).res + +all: $(PLUGIN_NAME).dll + +$(PLUGIN_NAME).rc : moduleinfo.nmake + sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ \ + -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ \ + -e s/@RC_VERSION@/$(RC_VERSION)/ \ + -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ \ + -e s/@PACKAGE@/$(PACKAGE)/ \ + -e s/@VERSION@/$(VERSION)/ \ + -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ \ + < plugin.rc.in > $@ + +$(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE) + link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \ + $(GLIB_LIBS) $(RESOURCE) + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +!IFDEF PYTHON +plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg.py + @echo Making plugin.c (using python) + @$(PYTHON) "../../tools/make-dissector-reg.py" . plugin $(DISSECTOR_SRC) +!ELSE +plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg + @echo Making plugin.c (using sh) + @$(SH) ../../tools/make-dissector-reg . plugin $(DISSECTOR_SRC) +!ENDIF + +!ENDIF + +clean: + rm -f $(OBJECTS) $(RESOURCE) plugin.c *.pdb \ + $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib \ + $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc + +distclean: clean + +maintainer-clean: distclean diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/README b/libbtbb-2015-10-R1/wireshark/plugins/btsm/README new file mode 100644 index 0000000..7013cce --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/README @@ -0,0 +1,14 @@ +BTSM Wireshark plugin +===================== + +This is the Bluetooth Low Energy Security Manager plugin for Wireshark. + +To build this on Debian/Ubuntu/BackTrack linux distributions: + sudo apt-get install wireshark-dev wireshark + cd libbtbb/wireshark/plugins/btsm/ + cmake . + make + make install + +This will install to the .wireshark/ in your home directory. To override +this set the DESTDIR environment variable when running cmake. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING new file mode 100644 index 0000000..53b6b71 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING-CMAKE-SCRIPTS b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..280ed6c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,27 @@ +Copyright notice for the files copied from +http://www.opensync.org/browser/branches/3rd-party-cmake-modules/modules + +$Id: COPYING-CMAKE-SCRIPTS 34248 2010-09-25 15:38:12Z jmayer $ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindGLIB2.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindGLIB2.cmake new file mode 100644 index 0000000..ae7badd --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindGLIB2.cmake @@ -0,0 +1,238 @@ +# +# $Id: FindGLIB2.cmake 34248 2010-09-25 15:38:12Z jmayer $ +# +# - Try to find GLib2 +# Once done this will define +# +# GLIB2_FOUND - system has GLib2 +# GLIB2_INCLUDE_DIRS - the GLib2 include directory +# GLIB2_LIBRARIES - Link these to use GLib2 +# +# HAVE_GLIB_GREGEX_H glib has gregex.h header and +# supports g_regex_match_simple +# +# Copyright (c) 2006 Andreas Schneider +# Copyright (c) 2006 Philippe Bernery +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Alban Browaeys +# Copyright (c) 2008 Michael Bell +# Copyright (c) 2008-2009 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +IF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + # in cache already + SET(GLIB2_FOUND TRUE) +ELSE (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS ) + + INCLUDE(FindPkgConfig) + + ## Glib + IF ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) + ELSE ( GLIB2_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) + ENDIF ( GLIB2_FIND_REQUIRED ) + + IF ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0>=${GLIB2_MIN_VERSION} ) + ELSE ( GLIB2_MIN_VERSION ) + PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0 ) + ENDIF ( GLIB2_MIN_VERSION ) + IF ( PKG_CONFIG_FOUND ) + IF ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( GLIB2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( GLIB2_FOUND ) + ENDIF ( PKG_CONFIG_FOUND ) + + # Look for glib2 include dir and libraries w/o pkgconfig + IF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( + _glibconfig_include_DIR + NAMES + glibconfig.h + PATHS + /opt/gnome/lib64 + /opt/gnome/lib + /opt/lib/ + /opt/local/lib + /sw/lib/ + /usr/lib64 + /usr/lib + /usr/local/include + ${CMAKE_LIBRARY_PATH} + PATH_SUFFIXES + glib-2.0/include + ) + + FIND_PATH( + _glib2_include_DIR + NAMES + glib.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + PATH_SUFFIXES + glib-2.0 + ) + + #MESSAGE(STATUS "Glib headers: ${_glib2_include_DIR}") + + FIND_LIBRARY( + _glib2_link_DIR + NAMES + glib-2.0 + glib + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + IF ( _glib2_include_DIR AND _glib2_link_DIR ) + SET ( _glib2_FOUND TRUE ) + ENDIF ( _glib2_include_DIR AND _glib2_link_DIR ) + + + IF ( _glib2_FOUND ) + SET ( GLIB2_INCLUDE_DIRS ${_glib2_include_DIR} ${_glibconfig_include_DIR} ) + SET ( GLIB2_LIBRARIES ${_glib2_link_DIR} ) + SET ( GLIB2_CORE_FOUND TRUE ) + ELSE ( _glib2_FOUND ) + SET ( GLIB2_CORE_FOUND FALSE ) + ENDIF ( _glib2_FOUND ) + + # Handle dependencies + # libintl + IF ( NOT LIBINTL_FOUND ) + FIND_PATH(LIBINTL_INCLUDE_DIR + NAMES + libintl.h + PATHS + /opt/gnome/include + /opt/local/include + /sw/include + /usr/include + /usr/local/include + ) + + FIND_LIBRARY(LIBINTL_LIBRARY + NAMES + intl + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/local/lib + /usr/lib + ) + + IF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + SET (LIBINTL_FOUND TRUE) + ENDIF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR) + ENDIF ( NOT LIBINTL_FOUND ) + + # libiconv + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR + NAMES + iconv.h + PATHS + /opt/gnome/include + /opt/local/include + /opt/local/include + /sw/include + /sw/include + /usr/local/include + /usr/include + PATH_SUFFIXES + glib-2.0 + ) + + FIND_LIBRARY(LIBICONV_LIBRARY + NAMES + iconv + PATHS + /opt/gnome/lib + /opt/local/lib + /sw/lib + /usr/lib + /usr/local/lib + ) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + + IF (LIBINTL_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBINTL_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBINTL_INCLUDE_DIR}) + ENDIF (LIBINTL_FOUND) + + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) + + ENDIF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND ) + ## + + IF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + SET (GLIB2_FOUND TRUE) + ENDIF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES) + + IF (GLIB2_FOUND) + IF (NOT GLIB2_FIND_QUIETLY) + MESSAGE (STATUS "Found GLib2: ${GLIB2_LIBRARIES} ${GLIB2_INCLUDE_DIRS}") + ENDIF (NOT GLIB2_FIND_QUIETLY) + ELSE (GLIB2_FOUND) + IF (GLIB2_FIND_REQUIRED) + MESSAGE (SEND_ERROR "Could not find GLib2") + ENDIF (GLIB2_FIND_REQUIRED) + ENDIF (GLIB2_FOUND) + + # show the GLIB2_INCLUDE_DIRS and GLIB2_LIBRARIES variables only in the advanced view + MARK_AS_ADVANCED(GLIB2_INCLUDE_DIRS GLIB2_LIBRARIES) + MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARY) + MARK_AS_ADVANCED(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARY) + +ENDIF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS) + +IF ( WIN32 ) + # include libiconv for win32 + IF ( NOT LIBICONV_FOUND ) + FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h PATH_SUFFIXES glib-2.0) + + FIND_LIBRARY(LIBICONV_LIBRARY NAMES iconv) + + IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + SET (LIBICONV_FOUND TRUE) + ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR) + ENDIF ( NOT LIBICONV_FOUND ) + IF (LIBICONV_FOUND) + SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY}) + SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR}) + ENDIF (LIBICONV_FOUND) +ENDIF ( WIN32 ) + +IF ( GLIB2_FOUND ) + # Check if system has a newer version of glib + # which supports g_regex_match_simple + INCLUDE( CheckIncludeFiles ) + SET( CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS} ) + CHECK_INCLUDE_FILES ( glib/gregex.h HAVE_GLIB_GREGEX_H ) + CHECK_INCLUDE_FILES ( glib/gchecksum.h HAVE_GLIB_GCHECKSUM_H ) + # Reset CMAKE_REQUIRED_INCLUDES + SET( CMAKE_REQUIRED_INCLUDES "" ) +ENDIF( GLIB2_FOUND ) diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindWireshark.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindWireshark.cmake new file mode 100644 index 0000000..16fabed --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/FindWireshark.cmake @@ -0,0 +1,28 @@ +# +# Try to find the wireshark library and its includes +# +# This snippet sets the following variables: +# WIRESHARK_FOUND True if wireshark library got found +# WIRESHARK_INCLUDE_DIRS Location of the wireshark headers +# WIRESHARK_LIBRARIES List of libraries to use wireshark +# +# Copyright (c) 2011 Reinhold Kainhofer +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# wireshark does not install its library with pkg-config information, +# so we need to manually find the libraries and headers + +FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/packet.h PATH_SUFFIXES wireshark ) +FIND_LIBRARY( WIRESHARK_LIBRARIES wireshark ) + +# Report results +IF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + SET( WIRESHARK_FOUND 1 ) +ELSE ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + MESSAGE( SEND_ERROR "Could NOT find the wireshark library and headers" ) +ENDIF ( WIRESHARK_LIBRARIES AND WIRESHARK_INCLUDE_DIRS ) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/UseMakeDissectorReg.cmake b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/UseMakeDissectorReg.cmake new file mode 100644 index 0000000..e7e1a73 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/cmake/UseMakeDissectorReg.cmake @@ -0,0 +1,33 @@ +# +# $Id: UseMakeDissectorReg.cmake 33616 2010-07-22 12:18:36Z stig $ +# +MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype ) + # FIXME: Only the Python stuff has been implemented + # Make this into a MACRO, to avoid duplication with plugins/.../ + #register.c: $(plugin_src) $(ALL_DISSECTORS_SRC) $(top_srcdir)/tools/make-dissector-reg \ + # $(top_srcdir)/tools/make-dissector-reg.py + # @if test -n "$(PYTHON)"; then \ + # echo Making register.c with python ; \ + # $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + # dissectors $(ALL_DISSECTORS_SRC) ; \ + # else \ + # echo Making register.c with shell script ; \ + # $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + # dissectors $(plugin_src) $(ALL_DISSECTORS_SRC) ; \ + # fi + set( _sources ${ARGN} ) + ADD_CUSTOM_COMMAND( + OUTPUT + ${_outputfile} + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ${CMAKE_CURRENT_SOURCE_DIR} + ${_registertype} + ${_sources} + DEPENDS + ${_sources} + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg + ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py + ) +ENDMACRO(REGISTER_DISSECTOR_FILES) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.h b/libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.h new file mode 100644 index 0000000..ba9ada1 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.h @@ -0,0 +1,17 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "btsm" + + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "0.0.1" + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.nmake b/libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.nmake new file mode 100644 index 0000000..a6d5bbc --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/moduleinfo.nmake @@ -0,0 +1,28 @@ +# +# $Id: moduleinfo.nmake 20155 2006-12-19 22:22:34Z jake $ +# + +# The name +PACKAGE=btsm + +# The version +MODULE_VERSION_MAJOR=0 +MODULE_VERSION_MINOR=0 +MODULE_VERSION_MICRO=0 +MODULE_VERSION_EXTRA=1 + +# +# The RC_VERSION should be comma-separated, not dot-separated, +# as per Graham Bloice's message in +# +# http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html +# +# "The RC_VERSION variable in config.nmake should be comma separated. +# This allows the resources to be built correctly and the version +# number to be correctly displayed in the explorer properties dialog +# for the executables, and XP's tooltip, rather than 0.0.0.0." +# + +MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA) +RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA) + diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/packet-btsm.c b/libbtbb-2015-10-R1/wireshark/plugins/btsm/packet-btsm.c new file mode 100644 index 0000000..5a068c1 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/packet-btsm.c @@ -0,0 +1,381 @@ +/* packet-btsm.c + * Routines for Bluetooth Low Energy Security Manager dissection + * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* needed for epan/gcc-4.x */ +#include +#include + +#define BTL2CAP_FIXED_CID_BTSM 0x0006 + +/* initialize the protocol and registered fields */ +static int proto_btsm = -1; +static int hf_btsm_command = -1; +static int hf_btsm_pairing_request_io_capability = -1; +static int hf_btsm_pairing_request_oob_data = -1; +static int hf_btsm_pairing_request_auth_req = -1; +static int hf_btsm_pairing_request_reserved = -1; +static int hf_btsm_pairing_request_mitm = -1; +static int hf_btsm_pairing_request_bonding_flags = -1; +static int hf_btsm_pairing_request_max_key_size = -1; +static int hf_btsm_pairing_request_initiator_key_distribution = -1; +static int hf_btsm_pairing_request_responder_key_distribution = -1; +static int hf_btsm_pairing_response_io_capability = -1; +static int hf_btsm_pairing_response_oob_data = -1; +static int hf_btsm_pairing_response_auth_req = -1; +static int hf_btsm_pairing_response_reserved = -1; +static int hf_btsm_pairing_response_mitm = -1; +static int hf_btsm_pairing_response_bonding_flags = -1; +static int hf_btsm_pairing_response_max_key_size = -1; +static int hf_btsm_pairing_response_initiator_key_distribution = -1; +static int hf_btsm_pairing_response_responder_key_distribution = -1; +static int hf_btsm_pairing_confirm_confirm = -1; +static int hf_btsm_pairing_random_random = -1; +static int hf_btsm_encryption_info_ltk = -1; + +static const value_string commands[] = { + { 0x00, "Reserved" }, + { 0x01, "Pairing Request" }, + { 0x02, "Pairing Response" }, + { 0x03, "Pairing Confirm" }, + { 0x04, "Pairing Random" }, + { 0x05, "Pairing Failed" }, + { 0x06, "Encryption Information" }, + { 0x07, "Master Identification" }, + { 0x08, "Identity Information" }, + { 0x09, "Identity Address Information" }, + { 0x0A, "Signing Information" }, + { 0x0B, "Security Request" }, + { 0, NULL } +}; + +static const value_string io_capability[] = { + { 0x00, "DisplayOnly" }, + { 0x01, "DisplayYesNo" }, + { 0x02, "KeyboardOnly" }, + { 0x03, "NoInputOutput" }, + { 0x04, "KeyboardDisplay" }, + { 0, NULL } +}; + +static const value_string oob_data[] = { + { 0x00, "OOB Authentication data not present" }, + { 0x01, "OOB Authentication data from remote device present" }, + { 0, NULL } +}; + +static const value_string bonding_flags[] = { + { 0x0, "No Bonding" }, + { 0x1, "Bonding" }, + { 0, NULL }, +}; + +/* initialize the subtree pointers */ +static gint ett_btsm = -1; +static gint ett_auth_req = -1; + +static void +dissect_pairing_request(tvbuff_t *tvb, proto_tree *tree) +{ + proto_item *auth_req_item; + proto_tree *auth_req_tree; + + proto_tree_add_item(tree, hf_btsm_pairing_request_io_capability, tvb, 1, 1, TRUE); + proto_tree_add_item(tree, hf_btsm_pairing_request_oob_data, tvb, 2, 1, TRUE); + + auth_req_item = proto_tree_add_item(tree, hf_btsm_pairing_request_auth_req, tvb, 3, 1, TRUE); + auth_req_tree = proto_item_add_subtree(auth_req_item, ett_auth_req); + proto_tree_add_item(auth_req_tree, hf_btsm_pairing_request_reserved, tvb, 3, 1, TRUE); + proto_tree_add_bits_item(auth_req_tree, hf_btsm_pairing_request_mitm, tvb, 3 * 8 + 5, 1, TRUE); + proto_tree_add_item(auth_req_tree, hf_btsm_pairing_request_bonding_flags, tvb, 3, 1, TRUE); + + // TODO: check that max key size iswithin [7,16] + proto_tree_add_item(tree, hf_btsm_pairing_request_max_key_size, tvb, 4, 1, TRUE); + proto_tree_add_item(tree, hf_btsm_pairing_request_initiator_key_distribution, tvb, 5, 1, TRUE); + proto_tree_add_item(tree, hf_btsm_pairing_request_responder_key_distribution, tvb, 6, 1, TRUE); +} + +static void +dissect_pairing_response(tvbuff_t *tvb, proto_tree *tree) +{ + proto_item *auth_req_item; + proto_tree *auth_req_tree; + + proto_tree_add_item(tree, hf_btsm_pairing_response_io_capability, tvb, 1, 1, TRUE); + proto_tree_add_item(tree, hf_btsm_pairing_response_oob_data, tvb, 2, 1, TRUE); + + auth_req_item = proto_tree_add_item(tree, hf_btsm_pairing_response_auth_req, tvb, 3, 1, TRUE); + auth_req_tree = proto_item_add_subtree(auth_req_item, ett_auth_req); + proto_tree_add_item(auth_req_tree, hf_btsm_pairing_response_reserved, tvb, 3, 1, TRUE); + proto_tree_add_bits_item(auth_req_tree, hf_btsm_pairing_response_mitm, tvb, 3 * 8 + 5, 1, TRUE); + proto_tree_add_item(auth_req_tree, hf_btsm_pairing_response_bonding_flags, tvb, 3, 1, TRUE); + + // TODO: check that max key size iswithin [7,16] + proto_tree_add_item(tree, hf_btsm_pairing_response_max_key_size, tvb, 4, 1, TRUE); + proto_tree_add_item(tree, hf_btsm_pairing_response_initiator_key_distribution, tvb, 5, 1, TRUE); + proto_tree_add_item(tree, hf_btsm_pairing_response_responder_key_distribution, tvb, 6, 1, TRUE); +} + +static void +dissect_pairing_confirm(tvbuff_t *tvb, proto_tree *tree) +{ + proto_tree_add_item(tree, hf_btsm_pairing_confirm_confirm, tvb, 1, 16, TRUE); +} + +static void +dissect_pairing_random(tvbuff_t *tvb, proto_tree *tree) +{ + proto_tree_add_item(tree, hf_btsm_pairing_random_random, tvb, 1, 16, TRUE); +} + +static void +dissect_encryption_info(tvbuff_t *tvb, proto_tree *tree) +{ + proto_tree_add_item(tree, hf_btsm_encryption_info_ltk, tvb, 1, 16, TRUE); +} + +/* dissect a packet */ +static void +dissect_btsm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *btsm_item; + proto_tree *btsm_tree; + guint8 command; + +#if 0 + /* sanity check: length */ + if (tvb_length(tvb) > 0 && tvb_length(tvb) < 9) + /* bad length: look for a different dissector */ + return 0; +#endif + + /* make entries in protocol column and info column on summary display */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BTLE Security Manager"); + + command = tvb_get_guint8(tvb, 0); + + /* see if we are being asked for details */ + if (tree) { + + /* create display subtree for the protocol */ + btsm_item = proto_tree_add_item(tree, proto_btsm, tvb, 0, tvb_length(tvb), TRUE); + btsm_tree = proto_item_add_subtree(btsm_item, ett_btsm); + + proto_tree_add_item(btsm_tree, hf_btsm_command, tvb, 0, 1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + if (command <= 0xb) { + col_set_str(pinfo->cinfo, COL_INFO, commands[command].strptr); + } else { + col_set_str(pinfo->cinfo, COL_INFO, "Unknown"); + } + } + + switch (command) { + // pairing request + case (0x1): + dissect_pairing_request(tvb, btsm_tree); + break; + case (0x2): + dissect_pairing_response(tvb, btsm_tree); + break; + case (0x3): + dissect_pairing_confirm(tvb, btsm_tree); + break; + case (0x4): + dissect_pairing_random(tvb, btsm_tree); + break; + case (0x6): + dissect_encryption_info(tvb, btsm_tree); + break; + default: + break; + } + } + + return; +} + +void +proto_reg_handoff_btsm(void) +{ + dissector_handle_t btsm_handle; + + btsm_handle = find_dissector("btsm"); + dissector_add_uint("btl2cap.cid", BTL2CAP_FIXED_CID_BTSM, btsm_handle); +} + +/* register the protocol with Wireshark */ +void +proto_register_btsm(void) +{ + + /* list of fields */ + static hf_register_info hf[] = { + { &hf_btsm_command, + { "Command", "btsm.command", + FT_UINT8, BASE_HEX, VALS(commands), 0x0, + NULL, HFILL } + }, + + // pairing request + { &hf_btsm_pairing_request_io_capability, + { "IO Capability", "btsm.pairing_request.io_capability", + FT_UINT8, BASE_HEX, VALS(io_capability), 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_oob_data, + { "OOB Data", "btsm.pairing_request.oob_data", + FT_UINT8, BASE_HEX, VALS(oob_data), 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_auth_req, + { "AuthReq", "btsm.pairing_request.auth_req", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_reserved, + { "Reserved", "btsm.pairing_request.auth_req.reserved", + FT_UINT8, BASE_HEX, NULL, 0xf8, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_mitm, + { "MITM Protection", "btsm.pairing_request.auth_req.mitm", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_bonding_flags, + { "Bonding Flags", "btsm.pairing_request.auth_req.bonding_flags", + FT_UINT8, BASE_HEX, VALS(bonding_flags), 0x3, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_max_key_size, + { "Max Key Size", "btsm.pairing_request.max_key_size", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_initiator_key_distribution, + { "Initiator Key Distribution", "btsm.pairing_request.initiator_key_distribution", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_request_responder_key_distribution, + { "Responder Key Distribution", "btsm.pairing_request.responder_key_distribution", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + // pairing response + { &hf_btsm_pairing_response_io_capability, + { "IO Capability", "btsm.pairing_response.io_capability", + FT_UINT8, BASE_HEX, VALS(io_capability), 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_oob_data, + { "OOB Data", "btsm.pairing_response.oob_data", + FT_UINT8, BASE_HEX, VALS(oob_data), 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_auth_req, + { "AuthReq", "btsm.pairing_response.auth_req", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_reserved, + { "Reserved", "btsm.pairing_response.auth_req.reserved", + FT_UINT8, BASE_HEX, NULL, 0xf8, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_mitm, + { "MITM Protection", "btsm.pairing_response.auth_req.mitm", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_bonding_flags, + { "Bonding Flags", "btsm.pairing_response.auth_req.bonding_flags", + FT_UINT8, BASE_HEX, VALS(bonding_flags), 0x3, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_max_key_size, + { "Max Key Size", "btsm.pairing_response.max_key_size", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_initiator_key_distribution, + { "Initiator Key Distribution", "btsm.pairing_response.initiator_key_distribution", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_btsm_pairing_response_responder_key_distribution, + { "Responder Key Distribution", "btsm.pairing_response.responder_key_distribution", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + + // pairing confirm + { &hf_btsm_pairing_confirm_confirm, + { "Confirm", "btsm.pairing_confirm.confirm", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + // pairing random + { &hf_btsm_pairing_random_random, + { "Random", "btsm.pairing_random.random", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + // encryption info LTK + { &hf_btsm_encryption_info_ltk, + { "LTK", "btsm.encryption_info.ltk", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + }; + + /* protocol subtree arrays */ + static gint *ett[] = { + &ett_btsm, + &ett_auth_req, + }; + + /* register the protocol name and description */ + proto_btsm = proto_register_protocol( + "Bluetooth Low Energy Security Manager", /* full name */ + "BTSM", /* short name */ + "btsm" /* abbreviation (e.g. for filters) */ + ); + + register_dissector("btsm", dissect_btsm, proto_btsm); + + /* register the header fields and subtrees used */ + proto_register_field_array(proto_btsm, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/plugin.rc.in b/libbtbb-2015-10-R1/wireshark/plugins/btsm/plugin.rc.in new file mode 100644 index 0000000..568dc07 --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/plugin.rc.in @@ -0,0 +1,34 @@ +#include "winver.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @RC_MODULE_VERSION@ + PRODUCTVERSION @RC_VERSION@ + FILEFLAGSMASK 0x0L +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0" + VALUE "FileDescription", "@PACKAGE@ dissector\0" + VALUE "FileVersion", "@MODULE_VERSION@\0" + VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0" + VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs , Gilbert Ramirez and others\0" + VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0" + VALUE "ProductName", "Wireshark\0" + VALUE "ProductVersion", "@VERSION@\0" + VALUE "Comments", "Build with @MSVC_VARIANT@\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg b/libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg new file mode 100755 index 0000000..d2efa7c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg.py b/libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg.py new file mode 100755 index 0000000..060460c --- /dev/null +++ b/libbtbb-2015-10-R1/wireshark/plugins/btsm/tools/make-dissector-reg.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $ + +import os +import sys +import re +import pickle +from stat import * + +VERSION_KEY = '_VERSION' +CUR_VERSION = '$Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $' + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin" or registertype == "plugin_wtap": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by Makefile or Makefile.nmake. + */ +""" +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" + preamble = """\ +/* + * Do not modify this file. + * + * It is created automatically by the "register.c" target in + * epan/dissectors/Makefile or Makefile.nmake using information in + * epan/dissectors/register-cache.pkl. + * + * You can force this file to be regenerated completely by deleting + * it along with epan/dissectors/register-cache.pkl. + */ +""" +else: + print(("Unknown output type '%s'" % registertype)) + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append(os.path.join(srcdir, file)) + +if len(filenames) < 1: + print("No files found") + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +wtap_reg_regex0 = r"^(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" +wtap_reg_regex1 = r"void\s+(?Pwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ( 'wtap_register', re.compile(wtap_reg_regex0) ), + ( 'wtap_register', re.compile(wtap_reg_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION: + cache = {VERSION_KEY: CUR_VERSION} + except: + cache = {VERSION_KEY: CUR_VERSION} + + print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1))) + +# Grep +cache_hits = 0 +cache_misses = 0 +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and filename in cache: + cdict = cache[filename] + if cur_mtime == cdict['mtime']: + cache_hits += 1 +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + regs['wtap_register'].extend(cdict['wtap_register']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache_misses += 1 + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + 'wtap_register': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses))) + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print("No protocol registrations found") + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() +regs['wtap_register'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write(preamble) + +# Make the routine to register all protocols +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin" or registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin" or registertype == "plugin_wtap": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +elif registertype == "plugin_wtap": + reg_code.write(""" +G_MODULE_EXPORT void +register_wtap_module(void) +{ +"""); + + for symbol in regs['wtap_register']: + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + reg_code.write(line) + + reg_code.write("}\n"); + reg_code.write("#endif\n"); +else: + reg_code.write(""" +static gulong proto_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['proto_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +static gulong handoff_reg_count(void) +{ +"""); + + line = " return %d;\n" % len(regs['handoff_reg']) + reg_code.write(line) + + reg_code.write(""" +} +"""); + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return proto_reg_count() + handoff_reg_count();" + reg_code.write(line) + + reg_code.write(""" +}\n +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) diff --git a/ubertooth_install.sh b/ubertooth_install.sh new file mode 100755 index 0000000..6fe3652 --- /dev/null +++ b/ubertooth_install.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# Purpose: Install ubertooth and crackle libraries +# Author: Paul Walko +# Last updated on: 12/17/16 +# ------------------------------------------------ + +# Setup +echo -e 'Installs the latest stable ubertooth release and/or crackle (git) release to /opt' +echo -e 'This script was only tested in Arch Linux (12/16). Your mileage may vary' +echo -e 'This script also assumes you have sudo access, as you will be prompted for your password\n' + +INSTALL_DIR="/opt" + +# help +function help { + echo -e 'Help:\n' + echo -e '-h: This message\n' + echo -e '-I: Custom installation directory; Defaults to '/opt/'\n' + echo -e '--remove-{libbtbb, ubertooth, crackle}: Removes respective program\n\n' +} + +# Set install directory +while getopts ":h:I:" args; do + case "${args}" in + h) + help + ;; + I) + INSTALL_DIR=${OPTARG} + ;; + *) + ;; + esac +done + +# libbtbb +cd $INSTALL_DIR +if [[ $* == *--remove-libbtbb* ]]; then + # Remove libbtbb + echo -e 'WARNING: THIS WILL REMOVE ANY FILES/DIRECTORIES WITH "libbtbb" IN THEIR NAME \nContinue? (y/N)\n' + read yn + if [[ $yn == y ]]; then + suod rm *libbtbb*gz + cd *libbtbb*/build + sudo make uninstall + cd $INSTALL_DIR + sudo rm -r *libbtbb* + fi +elif ! ls | grep -q "libbtbb"; then + echo -e 'Installing libbtbb... (Ubertooth dependency)\n' + + wget https://github.com/greatscottgadgets/libbtbb/archive/2015-10-R1.tar.gz -O libbtbb-2015-10-R1.tar.gz + tar xf libbtbb-2015-10-R1.tar.gz + cd libbtbb-2015-10-R1 + mkdir build + cd build + cmake .. + make + sudo make install +else + echo -e 'libbtbb is already installed... skipping \nRun with "--remove-libbtbb" before installing new version\n' +fi + +# ubertooth +cd $INSTALL_DIR +if [[ $* == *--remove-ubertooth* ]] +then + # Remove ubertooth + echo -e 'WARNING: THIS WILL REMOVE ANY FILES/DIRECTORIES WITH "ubertooth" IN THEIR NAME \nContinue? (y/N)\n' + read yn + if [[ $yn == y ]]; then + sudo rm *ubertooth*xz + cd *ubertooth*/host/build + sudo make uninstall + cd $INSTALL_DIR + sudo rm -r *ubertooth* + fi +elif ! type "ubertooth-util" > /dev/null; then + # Install ubertooth + echo -e 'Installing ubertooth...\n\n' + + wget https://github.com/greatscottgadgets/ubertooth/releases/download/2015-10-R1/ubertooth-2015-10-R1.tar.xz -O ubertooth-2015-10-R1.tar.xz + tar xf ubertooth-2015-10-R1.tar.xz + cd ubertooth-2015-10-R1/host + mkdir build + cd build + cmake .. + make + sudo make install +else + # Already installed + echo -e 'ubertoooth is alrady installed... skipping \nRun with "--remove-ubertooth" before installing new version\n' +fi + +# crackle +cd $INSTALL_DIR +if [[ $* == *--remove-crackle* ]] +then + # Remove crackle + echo -e 'Remove crackle? (y/N)\n' + read yn + if [[ $yn == y ]]; then + cd crackle + sudo make uninstall + cd $INSTALL_DIR + sudo rm -r crackle + fi +elif ! type "crackle" > /dev/null; then + echo -e 'Installing crackle... \n\n' + + git clone https://github.com/mikeryan/crackle.git + cd crackle + make + sudo make install +else + # Already installed + echo -e 'crackle is alrady installed.. skipping \nRun with "--remove-crackle" before installing new version\n' +fi + + +echo -e 'Running ldconfig to fix some libraries... \n' +sudo ldconfig + +echo -e 'If you plan to use wireshark to capture btle, be sure to follow the directions at the bottom of the page here to enable wireshark to recongize btle packets: \nhttps://github.com/greatscottgadgets/ubertooth/wiki/Capturing-BLE-in-Wireshark' diff --git a/ubertooth_ubuntu160401.sh b/ubertooth_ubuntu160401.sh deleted file mode 100755 index 60152f6..0000000 --- a/ubertooth_ubuntu160401.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -echo 'This script was only tested in Ubuntu 16.04.1. Your mileage may vary' -echo 'This script also assumes you have sudo access, as you will be prompted for your password' - -sudo apt-get install git cmake libusb-1.0-0-dev make gcc g++ libbluetooth-dev pkg-config libpcap-dev python-numpy python-pyside python-qt4 wireshark git - -git clone https://github.com/greatscottgadgets/libbtbb.git -cd libbtbb -mkdir build -cd build -cmake .. -make -sudo make install -sudo ldconfig -cd ../.. - -git clone https://github.com/greatscottgadgets/ubertooth.git -cd ubertooth/host -mkdir build -cd build -cmake .. -make -sudo make install -sudo ldconfig -cd ../../.. - -sudo apt-get install wireshark wireshark-dev libwireshark-dev cmake -cd libbtbb/wireshark/plugins/btbb -mkdir build -cd build -cmake -DCMAKE_INSTALL_LIBDIR=/usr/lib/x86_64-linux-gnu/wireshark/libwireshark3/plugins .. -make -sudo make install -cd ../../../../.. - -sudo apt-get install wireshark wireshark-dev libwireshark-dev cmake -cd libbtbb/wireshark/plugins/btbredr -mkdir build -cd build -cmake -DCMAKE_INSTALL_LIBDIR=/usr/lib/x86_64-linux-gnu/wireshark/libwireshark3/plugins .. -make -sudo make install -cd ../../../../.. - -echo 'Adding user to wireshark group...' -sudo dpkg-reconfigure wireshark-common -sudo gpasswd -a $USER wireshark - -echo 'If you plan to use wireshark to capture btle, be sure to follow the directions at the bottom of the page here to enable wireshark to recongize btle packets: https://github.com/greatscottgadgets/ubertooth/wiki/Capturing-BLE-in-Wireshark'