btsnoop.cc revision 16b3e929c25490ec05d7935f18962720ec7c96a4
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
1949120dc867c7818511b5afec461dfc97d17eef58Marie Janssen#define LOG_TAG "bt_snoop"
2049120dc867c7818511b5afec461dfc97d17eef58Marie Janssen
213e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <arpa/inet.h>
22a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <errno.h>
235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <fcntl.h>
244394720415f45db5caea73e1a05351ff98601fe0Pavlin Radoslavov#include <inttypes.h>
25933926c92e1378cc76bc9c149107e670c4872d4eScott James Remnant#include <limits.h>
26933926c92e1378cc76bc9c149107e670c4872d4eScott James Remnant#include <netinet/in.h>
27611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <stdbool.h>
28a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <stdio.h>
29a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <stdlib.h>
303e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <string.h>
315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <sys/stat.h>
32a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati#include <sys/time.h>
335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <unistd.h>
345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
35db554581079863974af8e1289646f5deea6fc044Marie Janssen#include "bt_types.h"
3689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include "hci/include/btsnoop.h"
3789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include "hci/include/btsnoop_mem.h"
38fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#include "hci_layer.h"
3944802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h"
409891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson#include "stack_config.h"
415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
42611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatitypedef enum {
43611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kCommandPacket = 1,
44611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kAclPacket = 2,
45611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kScoPacket = 3,
46611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  kEventPacket = 4
47a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati} packet_type_t;
485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
49a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati// Epoch in microseconds since 01/01/0000.
50a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavatistatic const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
525ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic const stack_config_t* stack_config;
53f1d68e95f34921361dced60b1b53e3fef8401f03Kim Schulz
549891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic int logfile_fd = INVALID_FD;
559891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic bool module_started;
569891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic bool is_logging;
579891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic bool logging_enabled_via_api;
589891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
599891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// TODO(zachoverflow): merge btsnoop and btsnoop_net together
60a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_open();
61a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_close();
625ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonvoid btsnoop_net_write(const void* data, size_t length);
635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
64796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbachstatic void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
655ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                                 bool is_received);
669891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void update_logging();
679891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
689891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// Module lifecycle functions
699891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
705ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic future_t* start_up(void) {
719891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  module_started = true;
729891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  update_logging();
739891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
749891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  return NULL;
759891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
769891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
775ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic future_t* shut_down(void) {
789891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  module_started = false;
799891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  update_logging();
809891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
819891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  return NULL;
829891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
839891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
84b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin RadoslavovEXPORT_SYMBOL extern const module_t btsnoop_module = {
855ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    .name = BTSNOOP_MODULE,
865ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    .init = NULL,
875ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    .start_up = start_up,
885ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    .shut_down = shut_down,
895ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    .clean_up = NULL,
905ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    .dependencies = {STACK_CONFIG_MODULE, NULL}};
919891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
929891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// Interface functions
939891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
949891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void set_api_wants_to_log(bool value) {
959891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  logging_enabled_via_api = value;
969891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  update_logging();
979891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
989891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
995ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic void capture(const BT_HDR* buffer, bool is_received) {
100796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
1019891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
10289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  btsnoop_mem_capture(buffer);
10389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
1045ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  if (logfile_fd == INVALID_FD) return;
1059891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1069891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  switch (buffer->event & MSG_EVT_MASK) {
1079891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_HC_TO_STACK_HCI_EVT:
1089891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kEventPacket, p, false);
1099891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1109891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_HC_TO_STACK_HCI_ACL:
1119891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_STACK_TO_HC_HCI_ACL:
1129891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kAclPacket, p, is_received);
1139891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1149891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_HC_TO_STACK_HCI_SCO:
1159891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_STACK_TO_HC_HCI_SCO:
1169891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kScoPacket, p, is_received);
1179891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1189891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    case MSG_STACK_TO_HC_HCI_CMD:
1199891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      btsnoop_write_packet(kCommandPacket, p, true);
1209891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      break;
1219891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  }
1229891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1239891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1245ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic const btsnoop_t interface = {set_api_wants_to_log, capture};
1259891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1265ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonconst btsnoop_t* btsnoop_get_interface() {
1279891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  stack_config = stack_config_get_interface();
1289891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  return &interface;
1299891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1309891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1319891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson// Internal functions
1329891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1331192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestrostatic uint64_t btsnoop_timestamp(void) {
1341192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  struct timeval tv;
1351192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  gettimeofday(&tv, NULL);
1361192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro
1371192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  // Timestamp is in microseconds.
1387dc4051b584bb056940afebda9d8ad3a48c046c3Ben YoungTae Kim  uint64_t timestamp = tv.tv_sec;
1397dc4051b584bb056940afebda9d8ad3a48c046c3Ben YoungTae Kim  timestamp *= (uint64_t)1000000ULL;
1401192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  timestamp += tv.tv_usec;
1411192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  timestamp += BTSNOOP_EPOCH_DELTA;
1421192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro  return timestamp;
1431192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro}
1441192df9f7e709b9d9508ac86cbf5099a3a7ffa0eTucker Sylvestro
1459891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonstatic void update_logging() {
1465ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  bool should_log = module_started && (logging_enabled_via_api ||
1475ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                                       stack_config->get_btsnoop_turned_on());
1489891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1495ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  if (should_log == is_logging) return;
1509891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1519891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  is_logging = should_log;
1529891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  if (should_log) {
1535ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    const char* log_path = stack_config->get_btsnoop_log_path();
15404bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson
15504bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    // Save the old log if configured to do so
15604bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    if (stack_config->get_btsnoop_should_save_last()) {
15704bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson      char last_log_path[PATH_MAX];
1584394720415f45db5caea73e1a05351ff98601fe0Pavlin Radoslavov      snprintf(last_log_path, PATH_MAX, "%s.%" PRIu64, log_path,
1594394720415f45db5caea73e1a05351ff98601fe0Pavlin Radoslavov               btsnoop_timestamp());
16004bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson      if (!rename(log_path, last_log_path) && errno != ENOENT)
1615ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson        LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
1625ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                  log_path, last_log_path, strerror(errno));
16304bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson    }
1649891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
16512aeda148b39f82d07733ad5c3eafcc9264707a1Ajay Panicker    mode_t prevmask = umask(0);
1665ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC,
1675ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
1689891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    if (logfile_fd == INVALID_FD) {
1695ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson      LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path,
1705ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                strerror(errno));
17104bb236d873005ccb5950cb8e8f1f348499e032eZach Johnson      is_logging = false;
17212aeda148b39f82d07733ad5c3eafcc9264707a1Ajay Panicker      umask(prevmask);
1739891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson      return;
1749891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    }
17512aeda148b39f82d07733ad5c3eafcc9264707a1Ajay Panicker    umask(prevmask);
1769891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1779891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
17895b9bc0e533545a14cf12877c72e0d96ab4370fdSrinu Jella    btsnoop_net_open();
1799891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  } else {
1805ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    if (logfile_fd != INVALID_FD) close(logfile_fd);
1819891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
1829891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    logfile_fd = INVALID_FD;
1839891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    btsnoop_net_close();
1849891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson  }
1859891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson}
1869891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
187796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbachtypedef struct {
188796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint32_t length_original;
189796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint32_t length_captured;
190796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint32_t flags;
191796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint32_t dropped_packets;
192796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint64_t timestamp;
193796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint8_t type;
194796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach} __attribute__((__packed__)) btsnoop_header_t;
195796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach
196796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbachstatic uint64_t htonll(uint64_t ll) {
19716b3e929c25490ec05d7935f18962720ec7c96a4Pavlin Radoslavov  const uint32_t l = 1;
19816b3e929c25490ec05d7935f18962720ec7c96a4Pavlin Radoslavov  if (*(reinterpret_cast<const uint8_t*>(&l)) == 1)
19916b3e929c25490ec05d7935f18962720ec7c96a4Pavlin Radoslavov    return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 |
20016b3e929c25490ec05d7935f18962720ec7c96a4Pavlin Radoslavov           htonl(ll >> 32);
20116b3e929c25490ec05d7935f18962720ec7c96a4Pavlin Radoslavov
202796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  return ll;
203a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati}
204a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
205796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbachstatic void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
2065ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                                 bool is_received) {
207796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint32_t length_he = 0;
208796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  uint32_t flags = 0;
209796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach
210a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  switch (type) {
211a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kCommandPacket:
212a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = packet[2] + 4;
213a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = 2;
214a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
215a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kAclPacket:
216a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = (packet[3] << 8) + packet[2] + 5;
217a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = is_received;
218a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
219a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kScoPacket:
220a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = packet[2] + 4;
221a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = is_received;
222a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
223a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati    case kEventPacket:
224a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      length_he = packet[1] + 3;
225a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      flags = 3;
226a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati      break;
227a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati  }
228a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
229796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  btsnoop_header_t header;
230796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  header.length_original = htonl(length_he);
231796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  header.length_captured = header.length_original;
232796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  header.flags = htonl(flags);
233796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  header.dropped_packets = 0;
234796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  header.timestamp = htonll(btsnoop_timestamp());
235796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  header.type = type;
236796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach
237796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  btsnoop_net_write(&header, sizeof(btsnoop_header_t));
238796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  btsnoop_net_write(packet, length_he - 1);
239796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach
240796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  if (logfile_fd != INVALID_FD) {
241796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach    iovec iov[] = {{&header, sizeof(btsnoop_header_t)},
242796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach                   {reinterpret_cast<void*>(packet), length_he - 1}};
243796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach    TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2));
244796523d32d5478b63d9a545ec6a4e26207742b0cAndre Eisenbach  }
245a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati}
246