def handleNexus5StackDump(self, hcipkt): checksum_correct = self.verifyChecksum(hcipkt.data[5:]) packet_type = u8(hcipkt.data[4]) if packet_type == 0x2C: data = hcipkt.data[6:] values = [u32(data[i:i + 4]) for i in range(0, 64, 4)] log.debug("Stack Dump (%s):\n%s" % ( "checksum correct" if checksum_correct else "checksum NOT correct", "\n".join([hex(x) for x in values]), )) if data[0] == "\x02": # This is the second stack dump event (contains register values) log.warn("Received Stack-Dump Event (contains %d registers):" % (u8(data[1]))) registers = ( "pc: 0x%08x lr: 0x%08x sp: 0x%08x r0: 0x%08x r1: 0x%08x\n" % (values[2], values[3], values[1], values[4], values[5])) registers += ( "r2: 0x%08x r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x\n" % tuple(values[6:11])) log.warn(registers) return True elif packet_type == 0xF0: # RAM dump self.handleRamDump(hcipkt.data[10:]) elif packet_type == 0x4C: # RAM dump (last frame) self.handleRamDump(hcipkt.data[10:]) # This is the last pkt ouput: self.finishStackDump() return True return False
def _setupSockets(self): self.hciport = random.randint(60000, 65535 - 1) log.debug( "_setupSockets: Selected random ports snoop=%d and inject=%d" % (self.hciport, self.hciport + 1) ) log.info( "Wireshark configuration (on Loopback interface): udp.port == %d || udp.port == %d" % (self.hciport, self.hciport + 1) ) # Create s_snoop socket self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.s_snoop.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.s_snoop.bind(("127.0.0.1", self.hciport)) self.s_snoop.settimeout(0.5) self.s_snoop.setblocking(True) # Create s_inject self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.s_inject.settimeout(0.5) self.s_inject.setblocking(True) # Create IOBluetoothExtended Object that listens for commands, # sends them to the Bluetooth chip and replies via UDP socket. if not self.replay: self.iobe = IOBE.alloc().initWith_and_( str(self.hciport + 1), str(self.hciport) ) else: self.iobe = None time.sleep(0.5) return True
def _setupSockets(self): """ Forward the HCI snoop and inject ports from the Android device to the host (using adb). Open TCP sockets (s_snoop, s_inject) to connect to the forwarded ports. Read the btsnoop header from the s_snoop socket in order to verify that the connection actually works correctly. """ # In order to support multiple parallel instances of InternalBlue # (with multiple attached Android devices) we must not hard code the # forwarded port numbers. Therefore we choose the port numbers # randomly and hope that they are not already in use. self.hciport = random.randint( 60000, 65534 ) # minus 1, as we are using hciport + 1 log.debug( "_setupSockets: Selected random ports snoop=%d and inject=%d" % (self.hciport, self.hciport + 1) ) # Forward ports 8872 and 8873. Ignore log.info() outputs by the adb function. saved_loglevel = context.log_level context.log_level = "warn" try: adb.adb(["forward", "tcp:%d" % (self.hciport), "tcp:8872"]) adb.adb(["forward", "tcp:%d" % (self.hciport + 1), "tcp:8873"]) except PwnlibException as e: log.warn("Setup adb port forwarding failed: " + str(e)) return False finally: context.log_level = saved_loglevel # Connect to hci injection port self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: self.s_inject.connect(("127.0.0.1", self.hciport + 1)) self.s_inject.settimeout(0.5) except socket.error: log.warn("Could not connect to adb. Is your device authorized?") return False # Connect to hci snoop log port self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s_snoop.connect(("127.0.0.1", self.hciport)) self.s_snoop.settimeout(0.5) # Read btsnoop header if self._read_btsnoop_hdr() == None: log.warn("Could not read btsnoop header") self.s_inject.close() self.s_snoop.close() self.s_inject = self.s_snoop = None context.log_level = "warn" adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport)]) adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport + 1)]) context.log_level = saved_loglevel return False return True
def handleRamDump(self, data): """ Data should be a byte string containing the address (4 byte) followed by the actual ram dump (at this address) """ addr = u32(data[:4]) if self.memdump_addr == None: self.memdump_addr = addr self.memdumps[addr - self.memdump_addr] = data[4:] log.debug("Stack dump handling addr %08x", addr - self.memdump_addr)
def _recvThreadFunc(self): log.debug("Receive Thread started.") if self.write_btsnooplog: log.warn("Writing btsnooplog is not supported with iOS.") while not self.exit_requested: # Little bit ugly: need to re-apply changes to the global context to the thread-copy context.log_level = self.log_level # read record data try: received_data = self.s_snoop.recv(1024) except socket.timeout: continue # this is ok. just try again without error log.debug("H4 Data: %s", received_data) (record_data, is_more) = self._getLatestH4Blob(new_data=received_data) while record_data is not None: # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py. record = (hci.parse_hci_packet(record_data), 0, 0, 0, 0, 0) log.debug("Recv: " + str(record[0])) # Put the record into all queues of registeredHciRecvQueues if their # filter function matches. for ( queue, filter_function, ) in ( self.registeredHciRecvQueues ): # TODO filter_function not working with bluez modifications try: queue.put(record, block=False) except queue2k.Full: log.warn( "recvThreadFunc: A recv queue is full. dropping packets.." ) # Call all callback functions inside registeredHciCallbacks and pass the # record as argument. for callback in self.registeredHciCallbacks: callback(record) # Check if the stackDumpReceiver has noticed that the chip crashed. if self.stackDumpReceiver.stack_dump_has_happend: # A stack dump has happend! log.warn( "recvThreadFunc: The controller send a stack dump. stopping.." ) self.exit_requested = True (record_data, is_more) = self._getLatestH4Blob() if not is_more: break log.debug("Receive Thread terminated.")
def _read_btsnoop_hdr(self): """ Read the btsnoop header (see RFC 1761) from the snoop socket (s_snoop). """ data = self.s_snoop.recv(16) if len(data) < 16: return None if (self.write_btsnooplog) and self.btsnooplog_file.tell() == 0: self.btsnooplog_file.write(data) self.btsnooplog_file.flush() btsnoop_hdr = ( data[:8], u32(data[8:12], endian="big"), u32(data[12:16], endian="big"), ) log.debug("BT Snoop Header: %s, version: %d, data link type: %d" % btsnoop_hdr) return btsnoop_hdr
def handleS10StackDump(self, hcipkt): """ Packets in stack dump: 1b 03 90: contains pc and r0 1b 03 9c 1b 03 00 (x3) 1b 03 f0 (whole ram) """ checksum_correct = self.verifyChecksum(hcipkt.data[3:]) packet_type = u8(hcipkt.data[2]) if packet_type == 0x90: data = hcipkt.data[4:] values = [u32(data[i:i + 4]) for i in range(0, 64 * 2, 4)] log.debug("Stack Dump (%s):\n%s" % ( "checksum correct" if checksum_correct else "checksum NOT correct", "\n".join([hex(x) for x in values]), )) # Values different than in other stack dump formats, experimental output! log.warn("Received S10 Stack-Dump Event (contains %d registers):" % (u8(data[1]))) registers = ( "pc: 0x%08x lr: 0x%08x sp: 0x%08x r0: 0x%08x r1: 0x%08x\n" % (values[16], values[17], values[23], values[19], values[20])) registers += ( "r2: 0x%08x r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x\n" % (values[21], values[22], values[23], values[24], values[25])) log.warn(registers) return True # log.info("%x" % u32(hcipkt.data[8:12])) # no last packet for S10e, just the size counts here... also is sometimes longer and sometimes shorter if packet_type == 0xF0 and u32(hcipkt.data[8:12]) == 0x230080: # This is the last pkt ouput: self.finishStackDump() return True return False
def _setupSockets(self): self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s_snoop.settimeout(2) self.s_snoop.connect((self.host, self.port)) log.debug("_setupSockets: Bound socket.") # same socket for input and output (this is different from adb here!) self.s_inject = Injector(self.s_snoop) # Write Header to btsnoop file (if file is still empty): if self.write_btsnooplog and self.btsnooplog_file.tell() == 0: # BT Snoop Header: btsnoop\x00, version: 1, data link type: 1002 btsnoop_hdr = (b"btsnoop\x00" + p32(1, endian="big") + p32(1002, endian="big")) with self.btsnooplog_file_lock: self.btsnooplog_file.write(btsnoop_hdr) self.btsnooplog_file.flush() return True
def _sendThreadFunc(self): log.debug("Send Thread started.") while not self.exit_requested: # Little bit ugly: need to re-apply changes to the global context to the thread-copy context.log_level = self.log_level # Wait for 'send task' in send queue try: task = self.sendQueue.get(timeout=0.5) except queue2k.Empty: continue # Extract the components of the task h4type, data, queue, filter_function = task # Prepend UART TYPE and length. out = p8(h4type) + p8(len(data)) + data # Send command to the chip using IOBluetoothExtended framework h4type, data, queue, filter_function = task data = bytearray(data) opcode = format(data[1], "02x") + format(data[0], "02x") log.debug("Sending command: 0x" + "".join(format(x, "02x") for x in data) + ", opcode: " + opcode) if not (h4type == 0x01 or h4type == 0x02): log.warn("H4 Type {0} not supported by macOS Core!".format( str(h4type))) if queue is not None: queue.put(None) continue # if the caller expects a response: register a queue to receive the response if queue is not None and filter_function is not None: recvQueue = queue2k.Queue(1) self.registerHciRecvQueue(recvQueue, filter_function) # Sending command self.s_inject.sendto(out, ("127.0.0.1", self.hciport + 1)) # if the caller expects a response: # Wait for the HCI event response by polling the recvQueue if queue is not None and filter_function is not None: try: record = recvQueue.get(timeout=10) hcipkt = record[0] data = hcipkt.data except queue2k.Empty: log.warn("_sendThreadFunc: No response from the firmware.") data = None self.unregisterHciRecvQueue(recvQueue) continue queue.put(data) self.unregisterHciRecvQueue(recvQueue) log.debug("Send Thread terminated.")
def _recvThreadFunc(self): log.debug("Receive Thread started.") while not self.exit_requested: # Little bit ugly: need to re-apply changes to the global context to the thread-copy context.log_level = self.log_level # read record data try: data, addr = self.s_snoop.recvfrom(1024) record_data = bytearray(data) except socket.timeout: continue # this is ok. just try again without error if not self.exit_requested: # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py. record = ( hci.parse_hci_packet(record_data), 0, 0, 0, 0, 0, ) # TODO not sure if this causes trouble? log.debug("Recv: " + str(record[0])) # Put the record into all queues of registeredHciRecvQueues if their # filter function matches. for ( queue, filter_function, ) in ( self.registeredHciRecvQueues ): # TODO filter_function not working with bluez modifications try: queue.put(record, block=False) except queue.Full: log.warn( "recvThreadFunc: A recv queue is full. dropping packets..>" + str(record_data) ) # Call all callback functions inside registeredHciCallbacks and pass the # record as argument. for callback in self.registeredHciCallbacks: callback(record) log.debug("Receive Thread terminated.")
def _recvThreadFunc(self): """ This is the run-function of the recvThread. It receives HCI events from the s_snoop socket. The HCI packets are encapsulated in btsnoop records (see RFC 1761). Received HCI packets are being put into the queues inside registeredHciRecvQueues and passed to the callback functions inside registeredHciCallbacks. The thread stops when exit_requested is set to True. It will do that on its own if it encounters a fatal error or the stackDumpReceiver reports that the chip crashed. """ log.debug("Receive Thread started.") while not self.exit_requested: # Little bit ugly: need to re-apply changes to the global context to the thread-copy context.log_level = self.log_level # Read the record header record_hdr = b"" while not self.exit_requested and len(record_hdr) < 24: try: recv_data = self.s_snoop.recv(24 - len(record_hdr)) log.debug("recvThreadFunc: received bt_snoop data " + bytes_to_hex(recv_data)) if len(recv_data) == 0: log.info( "recvThreadFunc: bt_snoop socket was closed by remote site. stopping recv thread..." ) self.exit_requested = True break record_hdr += recv_data except socket.timeout: pass # this is ok. just try again without error if not record_hdr or len(record_hdr) != 24: if not self.exit_requested: log.warn( "recvThreadFunc: Cannot recv record_hdr. stopping.") self.exit_requested = True break if self.write_btsnooplog: self.btsnooplog_file.write(record_hdr) self.btsnooplog_file.flush() orig_len, inc_len, flags, drops, time64 = struct.unpack( ">IIIIq", record_hdr) # Read the record data record_data = bytearray() while not self.exit_requested and len(record_data) < inc_len: try: recv_data = self.s_snoop.recv(inc_len - len(record_data)) if len(recv_data) == 0: log.info( "recvThreadFunc: bt_snoop socket was closed by remote site. stopping.." ) self.exit_requested = True break record_data += bytearray(recv_data) except socket.timeout: pass # this is ok. just try again without error if not record_data or len(record_data) != inc_len: if not self.exit_requested: log.warn("recvThreadFunc: Cannot recv data. stopping.") self.exit_requested = True break if self.write_btsnooplog: self.btsnooplog_file.write(record_data) self.btsnooplog_file.flush() try: parsed_time = self._btsnoop_parse_time(time64) except OverflowError: parsed_time = None # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py. record = ( hci.parse_hci_packet(record_data), orig_len, inc_len, flags, drops, parsed_time, ) log.debug("_recvThreadFunc Recv: [" + str(parsed_time) + "] " + str(record[0])) # Put the record into all queues of registeredHciRecvQueues if their # filter function matches. for queue, filter_function in self.registeredHciRecvQueues: if filter_function == None or filter_function(record): try: queue.put(record, block=False) except queue2k.Full: log.warn( "recvThreadFunc: A recv queue is full. dropping packets.." ) # Call all callback functions inside registeredHciCallbacks and pass the # record as argument. for callback in self.registeredHciCallbacks: callback(record) # Check if the stackDumpReceiver has noticed that the chip crashed. # if self.stackDumpReceiver and self.stackDumpReceiver.stack_dump_has_happend: # A stack dump has happend! # log.warn("recvThreadFunc: The controller sent a stack dump.") # self.exit_requested = True log.debug("Receive Thread terminated.")
def handleEvalStackDump(self, hcipkt): """ Handles a core dump from the evaluation board. To trigger a dump execute: sendhcicmd 0xfc4e e81e2000 This executes some memory set to ffff which is an invalid command. Many events like executing address 0x0 will only crash the chip but not trigger a proper stack dump. The evaluation board has quite a lot of memory, RAM dump takes ages... dbfw_coredump_exception_cm3() generates the following dumps: 2c: CoreDumpInfo 2c: CoreDumpCPURegs 90: CoreDumpCPURegsExtend f0: CoreDumpRAMImage 78: CoreDumpRAMImage EOF 9c: CoreDumpHWRegs 01: CoreDumpEnd :param hcipkt: stack dump packet :return: returns True if dump could be decoded. """ checksum_correct = self.verifyChecksum(hcipkt.data[3:]) packet_type = u8(hcipkt.data[2]) log.debug("packet type %x", packet_type) # TODO CoreDumpInfo (shows LMP/HCI version, memory dumps) # CoreDumpCPURegs if packet_type == 0x2C: data = hcipkt.data[4:] values = [u32(data[i:i + 4]) for i in range(0, 64, 4)] log.debug("Stack Dump (%s):\n%s" % ( "checksum correct" if checksum_correct else "checksum NOT correct", "\n".join([hex(x) for x in values]), )) if data[0] == "\x02": # This is the second stack dump event (contains register values) log.warn( "Received Evaluation Stack-Dump Event (contains %d registers):" % (u8(data[1]))) registers = ( "pc: 0x%08x lr: 0x%08x sp: 0x%08x r0: 0x%08x r1: 0x%08x\n" % (values[2], values[3], values[1], values[4], values[5])) registers += ( "r2: 0x%08x r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x\n" % tuple(values[6:11])) log.warn(registers) return True # CoreDumpRAMImage # TODO: Eval board produces this twice: # for 0x200000+0x50000 and 0x270000+0x10000 elif packet_type == 0xF0: self.handleRamDump(hcipkt.data[8:]) return True # Last packet produced by CoreDumpRAMImage elif packet_type == 0x78: # RAM dump (last frame), TODO not sure if this works # This is the last pkt ouput: log.info("End of stackdump block...") self.finishStackDump() return True # On a Raspberry Pi 3, the last packet of a stack dump is '1b0340df0338'.... so it's 0x40 elif packet_type == 0xE8: # FIXME Raspi memdump is divided in two parts! # address change from 0001fe38 to packet type e8 and then it's computing addr -0130000 # negative addr does not work with finishStackDump() # so even though the last packet is 0x40, let's just finish on 0xe8 log.info( "End of first stackdump block, writing to file and skipping second..." ) self.finishStackDump() return True return False
def getHciDeviceList(self): # type: () -> List[Device] """ Get a list of available HCI devices. The list is obtained by executing ioctl syscalls HCIGETDEVLIST and HCIGETDEVINFO. The returned list contains dictionaries with the following fields: dev_id : Internal ID of the device (e.g. 0) dev_name : Name of the device (e.g. "hci0") dev_bdaddr : MAC address (e.g. "00:11:22:33:44:55") dev_flags : Device flags as decimal number dev_flags_str : Device flags as String (e.g. "UP RUNNING" or "DOWN") """ # Open Bluetooth socket to execute ioctl's: try: s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) # Ticket 6: does not run on Windows with Kali subsystem except socket.error: log.warn( "Opening a local Bluetooth socket failed. Not running on native Linux?" ) return [] # Do ioctl(s,HCIGETDEVLIST,arg) to get the number of available devices: # arg is struct hci_dev_list_req (/usr/include/bluetooth/hci.h) arg = p32(16) # dl->dev_num = HCI_MAX_DEV which is 16 (little endian) arg += b"\x00" * (8 * 16) devices_raw = fcntl.ioctl(s.fileno(), HCIGETDEVLIST, arg) num_devices = u16(devices_raw[:2]) log.debug("Found %d HCI devices via ioctl(HCIGETDEVLIST)!" % num_devices) device_list = [] for dev_nr in range(num_devices): dev_struct_start = 4 + 8 * dev_nr dev_id = u16(devices_raw[dev_struct_start:dev_struct_start + 2]) # arg is struct hci_dev_info (/usr/include/bluetooth/hci.h) arg = p16(dev_id) # di->dev_id = <device_id> arg += b"\x00" * 20 # Enough space for name, bdaddr and flags dev_info_raw = bytearray( fcntl.ioctl(s.fileno(), HCIGETDEVINFO, arg)) dev_name = dev_info_raw[2:10].replace(b"\x00", b"").decode() dev_bdaddr = ":".join( ["%02X" % x for x in dev_info_raw[10:16][::-1]]) dev_flags = u32(dev_info_raw[16:20]) if dev_flags == 0: dev_flags_str = "DOWN" else: dev_flags_str = " ".join([ name for flag, name in zip( bin(dev_flags)[2:][::-1], [ "UP", "INIT", "RUNNING", "PSCAN", "ISCAN", "AUTH", "ENCRYPT", "INQUIRY", "RAW", "RESET", ], ) if flag == "1" ]) device_list.append({ "dev_id": dev_id, "dev_name": dev_name, "dev_bdaddr": dev_bdaddr, "dev_flags": dev_flags, "dev_flags_str": dev_flags_str, }) s.close() return cast("List[Device]", device_list)
def _setupSockets(self): """ Linux already allows to open HCI sockets to Bluetooth devices, they include H4 information, we simply use it. """ # Check if hci device is in state "UP". If not, set it to "UP" (requires root) device = [ dev for dev in self.getHciDeviceList() if dev["dev_name"] == self.interface ] if len(device) == 0: log.warn("Device not found: " + self.interface) return False device = device[0] if device["dev_flags"] == 0: log.warn("Device %s is DOWN!" % self.interface) log.info("Trying to set %s to state 'UP' (requires root)" % self.interface) if not self.bringHciDeviceUp(device["dev_id"]): log.warn("Failed to bring up %s." % self.interface) return False # TODO unload btusb module and check error messages here to give the user some output if sth fails # Connect to HCI socket self.s_snoop = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR, 1) self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP, 1) """ struct hci_filter { uint32_t type_mask; -> 4 uint32_t event_mask[2]; -> 8 uint16_t opcode; -> 2 }; """ # TODO still seems to only forward incoming events?! self.s_snoop.setsockopt( socket.SOL_HCI, socket.HCI_FILTER, b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00", ) # type mask, event mask, event mask, opcode interface_num = device["dev_id"] log.debug("Socket interface number: %s" % interface_num) self.s_snoop.bind((interface_num, )) self.s_snoop.settimeout(2) log.debug("_setupSockets: Bound socket.") # same socket for input and output (this is different from adb here!) self.s_inject = self.s_snoop # Write Header to btsnoop file (if file is still empty): if self.write_btsnooplog and self.btsnooplog_file.tell() == 0: # BT Snoop Header: btsnoop\x00, version: 1, data link type: 1002 btsnoop_hdr = (b"btsnoop\x00" + p32(1, endian="big") + p32(1002, endian="big")) with self.btsnooplog_file_lock: self.btsnooplog_file.write(btsnoop_hdr) self.btsnooplog_file.flush() return True
def _recvThreadFunc(self): """ This is the run-function of the recvThread. It receives HCI events from the s_snoop socket. The HCI packets are encapsulated in btsnoop records (see RFC 1761). Received HCI packets are being put into the queues inside registeredHciRecvQueues and passed to the callback functions inside registeredHciCallbacks. The thread stops when exit_requested is set to True. It will do that on its own if it encounters a fatal error or the stackDumpReceiver reports that the chip crashed. """ log.debug("Receive Thread started.") while not self.exit_requested: # Little bit ugly: need to re-apply changes to the global context to the thread-copy context.log_level = self.log_level # Read the record data try: record_data = self.s_snoop.recv(1024) record_data = bytearray(record_data) except socket.timeout: continue # this is ok. just try again without error except Exception as e: log.critical( "Lost device interface with exception {}, terminating receive thread..." .format(e)) self.exit_requested = True continue # btsnoop record header data: btsnoop_orig_len = len(record_data) btsnoop_inc_len = len(record_data) btsnoop_flags = 0 btsnoop_drops = 0 btsnoop_time = datetime.datetime.now() # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py. record = ( hci.parse_hci_packet(record_data), btsnoop_orig_len, btsnoop_inc_len, btsnoop_flags, btsnoop_drops, btsnoop_time, ) log.debug("_recvThreadFunc Recv: [" + str(btsnoop_time) + "] " + str(record[0])) # Write to btsnoop file: if self.write_btsnooplog: btsnoop_record_hdr = struct.pack( ">IIIIq", btsnoop_orig_len, btsnoop_inc_len, btsnoop_flags, btsnoop_drops, self._btsnoop_pack_time(btsnoop_time), ) with self.btsnooplog_file_lock: self.btsnooplog_file.write(btsnoop_record_hdr) self.btsnooplog_file.write(record_data) self.btsnooplog_file.flush() # Put the record into all queues of registeredHciRecvQueues if their # filter function matches. for queue, filter_function in self.registeredHciRecvQueues: if filter_function is None or filter_function(record): try: queue.put(record, block=False) except queue2k.Full: log.warn( "recvThreadFunc: A recv queue is full. dropping packets.." ) # Call all callback functions inside registeredHciCallbacks and pass the # record as argument. for callback in self.registeredHciCallbacks: callback(record) # Check if the stackDumpReceiver has noticed that the chip crashed. # if self.stackDumpReceiver.stack_dump_has_happend: # A stack dump has happend! # log.warn("recvThreadFunc: The controller send a stack dump.") # self.exit_requested = True log.debug("Receive Thread terminated.")