15738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/******************************************************************************
25738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
39891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson *  Copyright (C) 2014 Google, Inc.
45738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
55738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  Licensed under the Apache License, Version 2.0 (the "License");
65738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  you may not use this file except in compliance with the License.
75738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  You may obtain a copy of the License at:
85738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
95738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  http://www.apache.org/licenses/LICENSE-2.0
105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  See the License for the specific language governing permissions and
155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  limitations under the License.
165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project ******************************************************************************/
185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19985d4b6986b787839ba72470f96be841f7721a17Marie Janssen#define LOG_TAG "bt_snoop"
20985d4b6986b787839ba72470f96be841f7721a17Marie Janssen
213e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <arpa/inet.h>
22a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <assert.h>
23a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <errno.h>
245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <fcntl.h>
2512265e39b511f28425236b0dc97c78e7d837304bPavlin Radoslavov#include <inttypes.h>
26933926c92e1378cc76bc9c149107e670c4872d4eScott James Remnant#include <limits.h>
27933926c92e1378cc76bc9c149107e670c4872d4eScott James Remnant#include <netinet/in.h>
28611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <stdbool.h>
29a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <stdio.h>
30a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <stdlib.h>
313e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <string.h>
325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <sys/stat.h>
33a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <sys/time.h>
345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <unistd.h>
355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
36db554581079863974af8e1289646f5deea6fc044Marie Janssen#include "bt_types.h"
3789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include "hci/include/btsnoop.h"
3889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include "hci/include/btsnoop_mem.h"
39fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#include "hci_layer.h"
4044802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h"
419891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson#include "stack_config.h"
425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
43611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatitypedef enum {
44611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kCommandPacket = 1,
45611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kAclPacket = 2,
46611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kScoPacket = 3,
47611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kEventPacket = 4
48a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati} packet_type_t;
495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
50a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati// Epoch in microseconds since 01/01/0000.
51a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavatistatic const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
539891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic const stack_config_t *stack_config;
54f1d68e95f34921361dced60b1b53e3fef8401f03Kim Schulz
559891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic int logfile_fd = INVALID_FD;
569891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic bool module_started;
579891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic bool is_logging;
589891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic bool logging_enabled_via_api;
599891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
609891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// TODO(zachoverflow): merge btsnoop and btsnoop_net together
61a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_open();
62a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_close();
63a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_write(const void *data, size_t length);
645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
659891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received);
669891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void update_logging();
679891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
689891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// Module lifecycle functions
699891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
709891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic future_t *start_up(void) {
719891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  module_started = true;
729891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  update_logging();
739891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
749891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  return NULL;
759891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
769891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
779891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic future_t *shut_down(void) {
789891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  module_started = false;
799891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  update_logging();
809891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
819891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  return NULL;
829891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
839891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
841f81b64b337832452e9ba1f530e612a685aebb82Ian CoolidgeEXPORT_SYMBOL const module_t btsnoop_module = {
859891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  .name = BTSNOOP_MODULE,
869891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  .init = NULL,
879891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  .start_up = start_up,
889891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  .shut_down = shut_down,
899891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  .clean_up = NULL,
909891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  .dependencies = {
919891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    STACK_CONFIG_MODULE,
929891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    NULL
939891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  }
949891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson};
959891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
969891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// Interface functions
979891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
989891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void set_api_wants_to_log(bool value) {
999891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  logging_enabled_via_api = value;
1009891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  update_logging();
1019891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1029891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1039891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void capture(const BT_HDR *buffer, bool is_received) {
1049891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  const uint8_t *p = buffer->data + buffer->offset;
1059891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
10689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  btsnoop_mem_capture(buffer);
10789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
1089891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  if (logfile_fd == INVALID_FD)
1099891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    return;
1109891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1119891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  switch (buffer->event & MSG_EVT_MASK) {
1129891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_HC_TO_STACK_HCI_EVT:
1139891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kEventPacket, p, false);
1149891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1159891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_HC_TO_STACK_HCI_ACL:
1169891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_STACK_TO_HC_HCI_ACL:
1179891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kAclPacket, p, is_received);
1189891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1199891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_HC_TO_STACK_HCI_SCO:
1209891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_STACK_TO_HC_HCI_SCO:
1219891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kScoPacket, p, is_received);
1229891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1239891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_STACK_TO_HC_HCI_CMD:
1249891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kCommandPacket, p, true);
1259891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1269891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  }
1279891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1289891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1299891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic const btsnoop_t interface = {
1309891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  set_api_wants_to_log,
1319891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  capture
1329891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson};
1339891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1349891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonconst btsnoop_t *btsnoop_get_interface() {
1359891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  stack_config = stack_config_get_interface();
1369891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  return &interface;
1379891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1389891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1399891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// Internal functions
1409891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1411192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestrostatic uint64_t btsnoop_timestamp(void) {
1421192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  struct timeval tv;
1431192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  gettimeofday(&tv, NULL);
1441192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro
1451192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  // Timestamp is in microseconds.
1461192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  uint64_t timestamp = tv.tv_sec * 1000 * 1000LL;
1471192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  timestamp += tv.tv_usec;
1481192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  timestamp += BTSNOOP_EPOCH_DELTA;
1491192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  return timestamp;
1501192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro}
1511192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro
1529891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void update_logging() {
1539891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  bool should_log = module_started &&
1549891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    (logging_enabled_via_api || stack_config->get_btsnoop_turned_on());
1559891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1569891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  if (should_log == is_logging)
1579891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    return;
1589891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1599891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  is_logging = should_log;
1609891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  if (should_log) {
1619891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    btsnoop_net_open();
1629891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
16304bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    const char *log_path = stack_config->get_btsnoop_log_path();
16404bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson
16504bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    // Save the old log if configured to do so
16604bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    if (stack_config->get_btsnoop_should_save_last()) {
16704bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson      char last_log_path[PATH_MAX];
16812265e39b511f28425236b0dc97c78e7d837304bPavlin Radoslavov      snprintf(last_log_path, PATH_MAX, "%s.%" PRIu64, log_path,
16912265e39b511f28425236b0dc97c78e7d837304bPavlin Radoslavov               btsnoop_timestamp());
17004bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson      if (!rename(log_path, last_log_path) && errno != ENOENT)
171db554581079863974af8e1289646f5deea6fc044Marie Janssen        LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, log_path, last_log_path, strerror(errno));
17204bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    }
1739891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
17404bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
1759891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    if (logfile_fd == INVALID_FD) {
176db554581079863974af8e1289646f5deea6fc044Marie Janssen      LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path, strerror(errno));
17704bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson      is_logging = false;
1789891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      return;
1799891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    }
1809891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1819891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
1829891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  } else {
1839891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    if (logfile_fd != INVALID_FD)
1849891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      close(logfile_fd);
1859891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1869891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    logfile_fd = INVALID_FD;
1879891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    btsnoop_net_close();
1889891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  }
1899891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1909891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
191611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic void btsnoop_write(const void *data, size_t length) {
1929891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  if (logfile_fd != INVALID_FD)
1939891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    write(logfile_fd, data, length);
194a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
195a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_net_write(data, length);
196a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati}
197a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
198a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavatistatic void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) {
199227f6b08abb4e786a8951dde128388cd025ee63fChris Manton  int length_he = 0;
200a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  int length;
201a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  int flags;
202a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  int drops = 0;
203a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  switch (type) {
204a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kCommandPacket:
205a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = packet[2] + 4;
206a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = 2;
207a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
208a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kAclPacket:
209a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = (packet[3] << 8) + packet[2] + 5;
210a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = is_received;
211a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
212a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kScoPacket:
213a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = packet[2] + 4;
214a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = is_received;
215a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
216a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kEventPacket:
217a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = packet[1] + 3;
218a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = 3;
219a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
220a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  }
221a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
222a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  uint64_t timestamp = btsnoop_timestamp();
223a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  uint32_t time_hi = timestamp >> 32;
224a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  uint32_t time_lo = timestamp & 0xFFFFFFFF;
225a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
226a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  length = htonl(length_he);
227a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  flags = htonl(flags);
228a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  drops = htonl(drops);
229a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  time_hi = htonl(time_hi);
230a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  time_lo = htonl(time_lo);
231a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
232a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&length, 4);
233a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&length, 4);
234a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&flags, 4);
235a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&drops, 4);
236a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&time_hi, 4);
237a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&time_lo, 4);
238a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(&type, 1);
239a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  btsnoop_write(packet, length_he - 1);
240a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati}
241