// SPDX-License-Identifier: LGPL-2.1-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2014 Intel Corporation * Copyright (C) 2002-2010 Marcel Holtmann * * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "src/shared/btsnoop.h" #include "ellisys.h" static int ellisys_fd = -1; static uint16_t ellisys_index = 0xffff; void ellisys_enable(const char *server, uint16_t port) { struct sockaddr_in addr; int fd; if (ellisys_fd >= 0) { fprintf(stderr, "Ellisys injection already enabled\n"); return; } fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (fd < 0) { perror("Failed to open UDP injection socket"); return; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(server); addr.sin_port = htons(port); if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("Failed to connect UDP injection socket"); close(fd); return; } ellisys_fd = fd; } void ellisys_inject_hci(struct timeval *tv, uint16_t index, uint16_t opcode, const void *data, uint16_t size) { uint8_t msg[] = { /* HCI Injection Service, Version 1 */ 0x02, 0x00, 0x01, /* DateTimeNs Object */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Bitrate Object, 12000000 bps */ 0x80, 0x00, 0x1b, 0x37, 0x4b, /* HCI Packet Type Object */ 0x81, 0x00, /* HCI Packet Data Object */ 0x82 }; long nsec; time_t t; struct tm tm; struct iovec iov[2]; int iovcnt; if (!tv) return; if (ellisys_fd < 0) return; if (ellisys_index == 0xffff) ellisys_index = index; if (index != ellisys_index) return; t = tv->tv_sec; localtime_r(&t, &tm); nsec = ((tm.tm_sec + (tm.tm_min * 60) + (tm.tm_hour * 3600)) * 1000000l + tv->tv_usec) * 1000l; msg[4] = (1900 + tm.tm_year) & 0xff; msg[5] = (1900 + tm.tm_year) >> 8; msg[6] = (tm.tm_mon + 1) & 0xff; msg[7] = tm.tm_mday & 0xff; msg[8] = (nsec & 0x0000000000ffl); msg[9] = (nsec & 0x00000000ff00l) >> 8; msg[10] = (nsec & 0x000000ff0000l) >> 16; msg[11] = (nsec & 0x0000ff000000l) >> 24; msg[12] = (nsec & 0x00ff00000000l) >> 32; msg[13] = (nsec & 0xff0000000000l) >> 40; switch (opcode) { case BTSNOOP_OPCODE_COMMAND_PKT: msg[20] = 0x01; break; case BTSNOOP_OPCODE_EVENT_PKT: msg[20] = 0x84; break; case BTSNOOP_OPCODE_ACL_TX_PKT: msg[20] = 0x02; break; case BTSNOOP_OPCODE_ACL_RX_PKT: msg[20] = 0x82; break; case BTSNOOP_OPCODE_SCO_TX_PKT: msg[20] = 0x03; break; case BTSNOOP_OPCODE_SCO_RX_PKT: msg[20] = 0x83; break; case BTSNOOP_OPCODE_ISO_TX_PKT: msg[20] = 0x05; break; case BTSNOOP_OPCODE_ISO_RX_PKT: msg[20] = 0x85; break; default: return; } iov[0].iov_base = msg; iov[0].iov_len = sizeof(msg); if (size > 0) { iov[1].iov_base = (void *) data; iov[1].iov_len = size; iovcnt = 2; } else iovcnt = 1; if (writev(ellisys_fd, iov, iovcnt) < 0) perror("Failed to send Ellisys injection packet"); }