summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vishwanath KM <a21174@motorola.com> 2019-10-24 12:27:31 +0530
committer Vishwanath KM <a21174@motorola.com> 2019-10-24 12:44:37 +0530
commit5175c7927f8c5551d2b572cde902ec7ac2c24cdb (patch)
tree7c3aeebf77dc1fa2f4ac88dee1f1cd022045a55e
parent5a888f68d54f2b0c9a5a81b94433124a6d9485f5 (diff)
Add tool for live btsnoop logging with Frontline BT sniffer (FTS)
* This script supports Bluetooth Virtual Sniffing via Live Import feature of Frontline Bluetooth Sniffer(FTS). * It uses APIs from LiveImportAPI.dll in FTS path to communicate with FTS sniffer and inject HCI packets for live HCI sniffing
-rw-r--r--system/tools/scripts/btsnoop_live.py297
1 files changed, 297 insertions, 0 deletions
diff --git a/system/tools/scripts/btsnoop_live.py b/system/tools/scripts/btsnoop_live.py
new file mode 100644
index 0000000000..4e145ffea3
--- /dev/null
+++ b/system/tools/scripts/btsnoop_live.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python3
+###############################################################################################################
+#
+# Copyright (C) 2019 Motorola Mobility LLC
+#
+# 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 above copyright notice, this list of conditions and the
+# following disclaimer.
+#
+# 2. 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.
+#
+# 3. Neither the name of the copyright holder 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 HOLDER 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.
+#
+###############################################################################################################
+###############################################################################################################
+#
+# Bluetooth Virtual Sniffing for Android
+#
+# This script supports Bluetooth Virtual Sniffing via Live Import Feature of Frontline Bluetooth Sniffer(FTS)
+#
+# It extracts the HCI packets from Snoop logs and redirect it to FTS for live HCI sniffing.
+#
+# It uses liveimport.ini and LiveImportAPI.dll from FTS path to communicate with FTS sniffer software.
+#
+# It works on both Windows and Ubuntu. For Ubuntu, both FTS and Python should be installed on Wine.
+#
+# FTS_INI_PATH & FTS_DLL_PATH should be set to absolute path of liveimport.ini and LiveImportAPI.dll of FTS
+#
+# Example below - This may change per machine per FTS version in Windows vs Ubuntu (Wine), set accordingly.
+# For Windows
+# FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\'
+# FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\'
+#
+# For Ubuntu - FTS path recognized by Wine (not Ubuntu path)
+# FTS_INI_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\'
+# FTS_DLL_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\'
+#
+###############################################################################################################
+
+import os
+import platform
+import socket
+import struct
+import subprocess
+import sys
+import time
+if sys.version_info[0] >= 3:
+ import configparser
+else:
+ import ConfigParser as configparser
+
+from calendar import timegm
+from ctypes import byref, c_bool, c_longlong, CDLL
+from _ctypes import FreeLibrary
+from datetime import datetime
+
+
+# Update below to right path corresponding to your machine, FTS version and OS used.
+FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\'
+FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\Executables\\Core\\'
+
+
+iniName = 'liveimport.ini'
+if (platform.architecture()[0] == '32bit'):
+ dllName = 'LiveImportAPI.dll'
+else:
+ dllName = 'LiveImportAPI_x64.dll'
+
+launchFtsCmd = '\"'+FTS_DLL_PATH + 'fts.exe\"' + ' \"/ComProbe Protocol Analysis System=Generic\"' + ' \"/oemkey=Virtual\"'
+
+# Unix Epoch delta since 01/01/1970
+FILETIME_EPOCH_DELTA = 116444736000000000
+HUNDREDS_OF_NANOSECONDS = 10000000
+
+HOST = 'localhost'
+PORT = 8872
+SNOOP_ID = 16
+SNOOP_HDR = 24
+
+
+def get_file_time():
+ """
+ Obtain current time in file time format for display
+ """
+ date_time = datetime.now()
+ file_time = FILETIME_EPOCH_DELTA + (timegm(date_time.timetuple()) * HUNDREDS_OF_NANOSECONDS)
+ file_time = file_time + (date_time.microsecond * 10)
+ return file_time
+
+
+def get_connection_string():
+ """
+ Read ConnectionString from liveimport.ini
+ """
+ config = configparser.ConfigParser()
+ config.read(FTS_INI_PATH + iniName)
+ try:
+ conn_str = config.get('General', 'ConnectionString')
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ return None
+
+ return conn_str
+
+
+def get_configuration_string():
+ """
+ Read Configuration string from liveimport.ini
+ """
+ config_str = ''
+ config = configparser.ConfigParser()
+ config.read(FTS_INI_PATH + iniName)
+ try:
+ config_items = config.items('Configuration')
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ return None
+
+ if config_items is not None:
+ for item in config_items:
+ key, value = item
+ config_str += ("%s=%s\n" % (key, value))
+ return config_str
+ else:
+ return None
+
+def check_live_import_connection(live_import):
+ """
+ Launch FTS app in Virtual Sniffing Mode
+ Check if FTS App is ready to start receiving the data.
+ If not, wait until 1 min and exit if FTS didn't start.
+ """
+ is_connection_running = c_bool()
+ count = 0
+
+ status = live_import.IsAppReady(byref(is_connection_running))
+ if (is_connection_running.value == True):
+ print ("FTS is already launched, Start capture if not already started")
+ return True
+
+ print("Launching FTS Virtual Sniffing")
+ try:
+ ftsProcess = subprocess.Popen((launchFtsCmd), stdout=subprocess.PIPE)
+ except:
+ print("Error in Launching FTS.. exiting")
+ return False
+
+ while (is_connection_running.value == False and count < 12):
+ status = live_import.IsAppReady(byref(is_connection_running))
+ if (status < 0):
+ print("Live Import Internal Error %d" %(status))
+ return False
+ if (is_connection_running.value == False):
+ print("Waiting for 5 sec.. Open FTS Virtual Sniffing")
+ time.sleep(5)
+ count += 1
+ if (is_connection_running.value == True):
+ print ("FTS is ready to receive the data, Start capture now")
+ return True
+ else:
+ print("FTS Virtual Sniffing didn't start until 1 min.. exiting")
+ return False
+
+
+def init_live_import(conn_str, config_str):
+ """
+ Load DLL and Initialize the LiveImport module for FTS.
+ """
+ success = c_bool()
+ try:
+ live_import = CDLL(FTS_DLL_PATH + dllName)
+ except:
+ return None
+
+ if live_import is None:
+ print("Error: Path to LiveImportAPI.dll is incorrect.. exiting");
+ return None
+
+ print(dllName + " loaded successfully")
+ result = live_import.InitializeLiveImport(conn_str.encode('ascii', 'ignore'),
+ config_str.encode('ascii', 'ignore'),
+ byref(success))
+ if (result < 0):
+ print("Live Import Init failed")
+ return None
+ else:
+ print("Live Import Init success")
+ return live_import
+
+
+def release_live_import(live_import):
+ """
+ Cleanup and exit live import module.
+ """
+ if live_import is not None:
+ live_import.ReleaseLiveImport()
+ FreeLibrary(live_import._handle)
+
+
+def main():
+
+ print("Bluetooth Virtual Sniffing for Fluoride")
+ connection_str = get_connection_string()
+ if connection_str is None:
+ print("Error: path to liveimport.ini is incorrect.. exiting")
+ exit(0)
+
+ configuration_str = get_configuration_string()
+ if configuration_str is None:
+ print("Error: path to liveimport.ini is incorrect.. exiting")
+ exit(0)
+
+ live_import = init_live_import(connection_str, configuration_str)
+ if live_import is None:
+ print("Error: Path to LiveImportAPI.dll is incorrect.. exiting")
+ exit(0)
+
+ if (check_live_import_connection(live_import) == False):
+ release_live_import(live_import)
+ exit(0)
+
+ # Wait until the forward socket is ready
+ print("Waiting until adb is ready")
+ os.system('adb wait-for-device forward tcp:8872 tcp:8872')
+
+ btsnoop_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ btsnoop_sock.connect((HOST, PORT))
+ snoop_id = btsnoop_sock.recv(SNOOP_ID)
+ if not snoop_id.startswith(b"btsnoop"):
+ print("Error: Snoop ID wasn't received.. exiting")
+ release_live_import(live_import)
+ exit(0)
+
+ while True:
+ try:
+ snoop_hdr = btsnoop_sock.recv(SNOOP_HDR)
+ if snoop_hdr is not None:
+ try:
+ olen, ilen, flags = struct.unpack(">LLL", snoop_hdr[0:12])
+ except struct.error:
+ print("Error: Invalid data", repr(snoop_hdr))
+ continue
+
+ file_time = get_file_time()
+ timestamp = c_longlong(file_time)
+
+ snoop_data = b''
+ while (len(snoop_data) < olen):
+ data_frag = btsnoop_sock.recv(olen - len(snoop_data))
+ if data_frag is not None:
+ snoop_data += data_frag
+
+ print ("Bytes received %d Olen %d ilen %d flags %d" % (len(snoop_data), olen, ilen, flags))
+ packet_type = struct.unpack(">B", snoop_data[0:1])[0]
+ if packet_type == 1:
+ drf = 1
+ isend = 0
+ elif packet_type == 2:
+ drf = 2
+ if (flags & 0x01):
+ isend = 1
+ else:
+ isend = 0
+ elif packet_type == 3:
+ drf = 4
+ if (flags & 0x01):
+ isend = 1
+ else:
+ isend = 0
+ elif packet_type == 4:
+ drf = 8
+ isend = 1
+
+ result = live_import.SendFrame(olen-1, olen-1, snoop_data[1:olen], drf, isend, timestamp)
+ if (result < 0):
+ print("Send frame failed")
+ except KeyboardInterrupt:
+ print("Cleanup and exit")
+ release_live_import(live_import)
+ btsnoop_sock.close()
+ exit(0)
+
+
+if __name__ == '__main__':
+ main()
+