2020-09-22 03:00:30 +08:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
2014-01-04 14:43:05 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
|
|
*
|
2014-02-12 02:59:14 +08:00
|
|
|
* Copyright (C) 2011-2014 Intel Corporation
|
|
|
|
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
2014-01-04 14:43:05 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2018-12-07 04:28:18 +08:00
|
|
|
#define _GNU_SOURCE
|
2014-01-04 14:43:05 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/socket.h>
|
2014-01-07 16:05:46 +08:00
|
|
|
#include <sys/uio.h>
|
2014-01-04 14:43:05 +08:00
|
|
|
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2014-02-12 03:13:59 +08:00
|
|
|
#include "src/shared/btsnoop.h"
|
2014-01-04 14:43:05 +08:00
|
|
|
#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;
|
|
|
|
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");
|
|
|
|
}
|