mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 20:44:49 +00:00
Merge c9dd93687b
into eb50e99748
This commit is contained in:
commit
ace08aac69
13 changed files with 1010 additions and 0 deletions
|
@ -52,6 +52,11 @@
|
|||
; Controls whether dns.mitm logs to the sd card for debugging
|
||||
; 0 = Disabled, 1 = Enabled
|
||||
; enable_dns_mitm_debug_log = u8!0x0
|
||||
; Controls whether to enable uart mitm
|
||||
; for logging bluetooth HCI to btsnoop captures.
|
||||
; This is only implemented for [7.0.0+].
|
||||
; 0 = Do not enable, 1 = Enable.
|
||||
; enable_uart_mitm = u8!0x0
|
||||
[hbloader]
|
||||
; Controls the size of the homebrew heap when running as applet.
|
||||
; If set to zero, all available applet memory is used as heap.
|
||||
|
|
|
@ -38,3 +38,14 @@ It does so in order to enable user configuration of system settings, which are p
|
|||
dns_mitm enables intercepting requests to dns resolution services, to enable redirecting requests for specified hostnames.
|
||||
|
||||
For documentation, see [here](../../features/dns_mitm.md).
|
||||
|
||||
## uart_mitm
|
||||
`uart_mitm` intercepts the uart service used by bluetooth, on 7.0.0+ when enabled by [system_settings.ini](../../features/configurations.md). This allows logging bluetooth traffic.
|
||||
|
||||
Usage of bluetooth devices will be less responsive when this is enabled.
|
||||
|
||||
Logs are written to directory `/atmosphere/uart_logs/{PosixTime}_{TickTimestamp}_{ProgramId}`, which then contains the following:
|
||||
+ `cmd_log` Text log for uart IPortSession commands, and any warning messages.
|
||||
+ `btsnoop_hci.log` Bluetooth HCI log in the btsnoop format. This file is not accessible while it's the current log being used with HOS running.
|
||||
|
||||
4 directories are created for each system-boot. btsnoop logging is disabled for the first 3, with only the 4th enabled (enabled when a certain HCI vendor command is detected).
|
||||
|
|
|
@ -109,6 +109,9 @@ namespace ams::impl {
|
|||
AMS_DEFINE_SYSTEM_THREAD(21, settings, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, settings, IpcServer);
|
||||
|
||||
/* Bus. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-12, uart, IpcServer);
|
||||
|
||||
/* erpt. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, erpt, IpcServer);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "ns_mitm/nsmitm_module.hpp"
|
||||
#include "dns_mitm/dnsmitm_module.hpp"
|
||||
#include "sysupdater/sysupdater_module.hpp"
|
||||
#include "uart_mitm/uartmitm_module.hpp"
|
||||
|
||||
namespace ams::mitm {
|
||||
|
||||
|
@ -37,6 +38,7 @@ namespace ams::mitm {
|
|||
ModuleId_NsMitm,
|
||||
ModuleId_DnsMitm,
|
||||
ModuleId_Sysupdater,
|
||||
ModuleId_UartMitm,
|
||||
|
||||
ModuleId_Count,
|
||||
};
|
||||
|
@ -70,6 +72,7 @@ namespace ams::mitm {
|
|||
GetModuleDefinition<ns::MitmModule>(),
|
||||
GetModuleDefinition<socket::resolver::MitmModule>(),
|
||||
GetModuleDefinition<sysupdater::MitmModule>(),
|
||||
GetModuleDefinition<uart::MitmModule>(),
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -362,6 +362,12 @@ namespace ams::settings::fwdbg {
|
|||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_dns_mitm_debug_log", "u8!0x0"));
|
||||
|
||||
/* Controls whether to enable uart mitm */
|
||||
/* for logging bluetooth HCI to btsnoop captures. */
|
||||
/* This is only implemented for [7.0.0+]. */
|
||||
/* 0 = Do not enable, 1 = Enable. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_uart_mitm", "u8!0x0"));
|
||||
|
||||
/* Hbloader custom settings. */
|
||||
|
||||
/* Controls the size of the homebrew heap when running as applet. */
|
||||
|
|
257
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.cpp
Normal file
257
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "uart_mitm_logger.hpp"
|
||||
#include "../amsmitm_fs_utils.hpp"
|
||||
|
||||
namespace ams::mitm::uart {
|
||||
|
||||
alignas(os::ThreadStackAlignment) u8 g_logger_stack[0x1000];
|
||||
|
||||
std::shared_ptr<UartLogger> g_logger;
|
||||
|
||||
UartLogger::UartLogger() : m_request_event(os::EventClearMode_ManualClear), m_finish_event(os::EventClearMode_ManualClear), m_client_queue(m_client_queue_list, this->QueueSize), m_thread_queue(m_thread_queue_list, this->QueueSize) {
|
||||
for (size_t i=0; i<this->QueueSize; i++) {
|
||||
UartLogMessage *msg = &this->m_queue_list_msgs[i];
|
||||
std::memset(msg, 0, sizeof(UartLogMessage));
|
||||
|
||||
msg->data = static_cast<u8 *>(std::malloc(this->QueueBufferSize));
|
||||
AMS_ABORT_UNLESS(msg->data != nullptr);
|
||||
std::memset(msg->data, 0, this->QueueBufferSize);
|
||||
|
||||
this->m_client_queue.Send(reinterpret_cast<uintptr_t>(msg));
|
||||
}
|
||||
|
||||
/* Create and start the logger thread. */
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->m_thread), this->ThreadEntry, this, g_logger_stack, sizeof(g_logger_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(uart, IpcServer) - 2));
|
||||
os::StartThread(std::addressof(this->m_thread));
|
||||
}
|
||||
|
||||
UartLogger::~UartLogger() {
|
||||
/* Tell the logger thread to exit. */
|
||||
UartLogMessage *msg=nullptr;
|
||||
this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
|
||||
|
||||
msg->type = 0;
|
||||
|
||||
this->m_finish_event.Clear();
|
||||
this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
|
||||
this->m_request_event.Signal();
|
||||
|
||||
/* Wait on the logger thread, then destroy it. */
|
||||
os::WaitThread(std::addressof(this->m_thread));
|
||||
os::DestroyThread(std::addressof(this->m_thread));
|
||||
|
||||
for (size_t i=0; i<this->QueueSize; i++) {
|
||||
UartLogMessage *msg = &this->m_queue_list_msgs[i];
|
||||
std::free(msg->data);
|
||||
msg->data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UartLogger::ThreadFunction() {
|
||||
bool exit_flag=false;
|
||||
|
||||
this->m_cache_count = 0;
|
||||
this->m_cache_pos = 0;
|
||||
std::memset(this->m_cache_list, 0, sizeof(this->m_cache_list));
|
||||
std::memset(this->m_cache_buffer, 0, sizeof(this->m_cache_buffer));
|
||||
|
||||
while (!exit_flag) {
|
||||
this->m_request_event.Wait();
|
||||
|
||||
/* Receive messages, process them, then Send them. */
|
||||
UartLogMessage *msg=nullptr;
|
||||
while (this->m_thread_queue.TryReceive(reinterpret_cast<uintptr_t *>(&msg))) {
|
||||
if (msg->type==0) {
|
||||
exit_flag = true;
|
||||
}
|
||||
else if (msg->type==1) {
|
||||
this->WriteCache(msg);
|
||||
}
|
||||
else if (msg->type==2) {
|
||||
this->WriteCmdLog(reinterpret_cast<const char*>(msg->data), reinterpret_cast<const char*>(&msg->data[std::strlen((const char*)msg->data)+1]), msg->file_pos);
|
||||
}
|
||||
else if (msg->type==3) {
|
||||
this->FlushCache();
|
||||
}
|
||||
this->m_client_queue.Send(reinterpret_cast<uintptr_t>(msg));
|
||||
}
|
||||
|
||||
this->m_request_event.Clear();
|
||||
this->m_finish_event.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the thread to finish processing messages. */
|
||||
void UartLogger::WaitFinished() {
|
||||
/* Tell the thread to flush the cache. */
|
||||
UartLogMessage *msg=nullptr;
|
||||
this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
|
||||
|
||||
msg->type = 3;
|
||||
|
||||
this->m_finish_event.Clear();
|
||||
this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
|
||||
this->m_request_event.Signal();
|
||||
|
||||
/* Wait for processing to finish. */
|
||||
m_finish_event.Wait();
|
||||
}
|
||||
|
||||
/* Initialize the specified btsnoop log file. */
|
||||
void UartLogger::InitializeDataLog(FsFile *f, size_t *datalog_pos) {
|
||||
*datalog_pos = 0;
|
||||
|
||||
/* Setup the btsnoop header. */
|
||||
|
||||
struct {
|
||||
char id[8];
|
||||
u32 version;
|
||||
u32 datalink_type;
|
||||
} btsnoop_header = { .id = "btsnoop" };
|
||||
|
||||
u32 version = 1;
|
||||
u32 datalink_type = 1002; /* HCI UART (H4) */
|
||||
ams::util::StoreBigEndian(&btsnoop_header.version, version);
|
||||
ams::util::StoreBigEndian(&btsnoop_header.datalink_type, datalink_type);
|
||||
|
||||
/* Write the btsnoop header to the datalog. */
|
||||
this->WriteLog(f, datalog_pos, &btsnoop_header, sizeof(btsnoop_header));
|
||||
}
|
||||
|
||||
/* Flush the cache into the file. */
|
||||
void UartLogger::FlushCache() {
|
||||
for (size_t i=0; i<this->m_cache_count; i++) {
|
||||
UartLogMessage *cache_msg=&this->m_cache_list[i];
|
||||
this->WriteLogPacket(cache_msg->datalog_file, cache_msg->file_pos, cache_msg->timestamp, cache_msg->dir, cache_msg->data, cache_msg->size);
|
||||
}
|
||||
|
||||
this->m_cache_count = 0;
|
||||
this->m_cache_pos = 0;
|
||||
}
|
||||
|
||||
/* Write the specified message into the cache. */
|
||||
/* dir: false = Send (host->controller), true = Receive (controller->host). */
|
||||
void UartLogger::WriteCache(UartLogMessage *msg) {
|
||||
if (this->m_cache_count >= this->CacheListSize || this->m_cache_pos + msg->size >= this->CacheBufferSize) {
|
||||
this->FlushCache();
|
||||
}
|
||||
|
||||
UartLogMessage *cache_msg=&this->m_cache_list[this->m_cache_count];
|
||||
*cache_msg = *msg;
|
||||
cache_msg->data = &this->m_cache_buffer[this->m_cache_pos];
|
||||
std::memcpy(cache_msg->data, msg->data, msg->size);
|
||||
this->m_cache_count++;
|
||||
this->m_cache_pos+= msg->size;
|
||||
}
|
||||
|
||||
/* Append the specified string to the text file. */
|
||||
void UartLogger::WriteCmdLog(const char *path, const char *str, size_t *file_pos) {
|
||||
Result rc=0;
|
||||
FsFile file={};
|
||||
size_t len = std::strlen(str);
|
||||
rc = ams::mitm::fs::OpenAtmosphereSdFile(&file, path, FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = fsFileWrite(&file, *file_pos, str, len, FsWriteOption_None);
|
||||
}
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*file_pos += len;
|
||||
}
|
||||
fsFileClose(&file);
|
||||
}
|
||||
|
||||
/* Append the specified data to the datalog file. */
|
||||
void UartLogger::WriteLog(FsFile *f, size_t *datalog_pos, const void* buffer, size_t size) {
|
||||
if (R_SUCCEEDED(fsFileWrite(f, *datalog_pos, buffer, size, FsWriteOption_None))) {
|
||||
*datalog_pos += size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append the specified packet to the datalog via WriteLog. */
|
||||
/* dir: false = Send (host->controller), true = Receive (controller->host). */
|
||||
void UartLogger::WriteLogPacket(FsFile *f, size_t *datalog_pos, s64 timestamp, bool dir, const void* buffer, size_t size) {
|
||||
struct {
|
||||
u32 original_length;
|
||||
u32 included_length;
|
||||
u32 packet_flags;
|
||||
u32 cumulative_drops;
|
||||
s64 timestamp_microseconds;
|
||||
} pkt_hdr = {};
|
||||
|
||||
u32 flags = 0;
|
||||
if (dir) {
|
||||
flags |= BIT(0);
|
||||
}
|
||||
ams::util::StoreBigEndian(&pkt_hdr.original_length, static_cast<u32>(size));
|
||||
ams::util::StoreBigEndian(&pkt_hdr.included_length, static_cast<u32>(size));
|
||||
ams::util::StoreBigEndian(&pkt_hdr.packet_flags, flags);
|
||||
ams::util::StoreBigEndian(&pkt_hdr.timestamp_microseconds, timestamp);
|
||||
|
||||
this->WriteLog(f, datalog_pos, &pkt_hdr, sizeof(pkt_hdr));
|
||||
this->WriteLog(f, datalog_pos, buffer, size);
|
||||
}
|
||||
|
||||
/* Send the specified data to the Logger thread. */
|
||||
/* dir: false = Send (host->controller), true = Receive (controller->host). */
|
||||
bool UartLogger::SendLogData(FsFile *f, size_t *file_pos, s64 timestamp_base, s64 tick_base, bool dir, const void* buffer, size_t size) {
|
||||
/* Ignore log data which is too large. */
|
||||
if (size > this->QueueBufferSize) return false;
|
||||
|
||||
UartLogMessage *msg=nullptr;
|
||||
this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
|
||||
AMS_ABORT_UNLESS(msg->data != nullptr);
|
||||
|
||||
/* Setup the msg and send it. */
|
||||
msg->type = 1;
|
||||
msg->dir = dir;
|
||||
if (timestamp_base) {
|
||||
msg->timestamp = (armTicksToNs(armGetSystemTick() - tick_base) / 1000) + timestamp_base;
|
||||
}
|
||||
else {
|
||||
msg->timestamp = 0;
|
||||
}
|
||||
msg->datalog_file = f;
|
||||
msg->file_pos = file_pos;
|
||||
msg->size = size;
|
||||
std::memcpy(msg->data, buffer, size);
|
||||
|
||||
this->m_finish_event.Clear();
|
||||
this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
|
||||
this->m_request_event.Signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Send the specified text log to the Logger thread. */
|
||||
void UartLogger::SendTextLogData(const char *path, size_t *file_pos, const char *str) {
|
||||
/* Ignore log data which is too large. */
|
||||
if (std::strlen(path)+1 + std::strlen(str)+1 > this->QueueBufferSize) return;
|
||||
|
||||
UartLogMessage *msg=nullptr;
|
||||
this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
|
||||
AMS_ABORT_UNLESS(msg->data != nullptr);
|
||||
|
||||
/* Setup the msg and send it. */
|
||||
msg->type = 2;
|
||||
msg->file_pos = file_pos;
|
||||
std::memcpy(msg->data, path, std::strlen(path)+1);
|
||||
std::memcpy(&msg->data[std::strlen(path)+1], str, std::strlen(str)+1);
|
||||
|
||||
this->m_finish_event.Clear();
|
||||
this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
|
||||
this->m_request_event.Signal();
|
||||
}
|
||||
}
|
75
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.hpp
Normal file
75
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::mitm::uart {
|
||||
|
||||
struct UartLogMessage {
|
||||
u8 type;
|
||||
bool dir;
|
||||
s64 timestamp;
|
||||
FsFile *datalog_file;
|
||||
size_t *file_pos;
|
||||
size_t size;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
class UartLogger {
|
||||
private:
|
||||
ams::os::ThreadType m_thread;
|
||||
os::Event m_request_event;
|
||||
os::Event m_finish_event;
|
||||
os::MessageQueue m_client_queue;
|
||||
os::MessageQueue m_thread_queue;
|
||||
|
||||
static constexpr inline size_t QueueSize = 0x20;
|
||||
static constexpr inline size_t QueueBufferSize = 0x400;
|
||||
static constexpr inline size_t CacheListSize = 0x80;
|
||||
static constexpr inline size_t CacheBufferSize = 0x1000;
|
||||
|
||||
uintptr_t m_client_queue_list[QueueSize];
|
||||
uintptr_t m_thread_queue_list[QueueSize];
|
||||
UartLogMessage m_queue_list_msgs[QueueSize];
|
||||
|
||||
size_t m_cache_count;
|
||||
size_t m_cache_pos;
|
||||
UartLogMessage m_cache_list[CacheListSize];
|
||||
u8 m_cache_buffer[CacheBufferSize];
|
||||
|
||||
static void ThreadEntry(void *arg) { static_cast<UartLogger *>(arg)->ThreadFunction(); }
|
||||
void ThreadFunction();
|
||||
|
||||
void FlushCache();
|
||||
void WriteCache(UartLogMessage *msg);
|
||||
|
||||
void WriteCmdLog(const char *path, const char *str, size_t *file_pos);
|
||||
void WriteLog(FsFile *f, size_t *datalog_pos, const void* buffer, size_t size);
|
||||
void WriteLogPacket(FsFile *f, size_t *datalog_pos, s64 timestamp, bool dir, const void* buffer, size_t size);
|
||||
public:
|
||||
UartLogger();
|
||||
~UartLogger();
|
||||
|
||||
void WaitFinished();
|
||||
|
||||
void InitializeDataLog(FsFile *f, size_t *datalog_pos);
|
||||
|
||||
bool SendLogData(FsFile *f, size_t *file_pos, s64 timestamp_base, s64 tick_base, bool dir, const void* buffer, size_t size);
|
||||
void SendTextLogData(const char *path, size_t *file_pos, const char *str);
|
||||
};
|
||||
|
||||
extern std::shared_ptr<UartLogger> g_logger;
|
||||
}
|
322
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.cpp
Normal file
322
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.cpp
Normal file
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "uart_mitm_service.hpp"
|
||||
#include "uart_mitm_logger.hpp"
|
||||
#include "../amsmitm_fs_utils.hpp"
|
||||
|
||||
namespace ams::mitm::uart {
|
||||
|
||||
/* Helper functions. */
|
||||
bool UartPortService::TryGetCurrentTimestamp(u64 *out) {
|
||||
/* Clear output. */
|
||||
*out = 0;
|
||||
|
||||
/* Check if we have time service. */
|
||||
{
|
||||
bool has_time_service = false;
|
||||
if (R_FAILED(sm::HasService(&has_time_service, sm::ServiceName::Encode("time:s"))) || !has_time_service) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to get the current time. */
|
||||
{
|
||||
sm::ScopedServiceHolder<timeInitialize, timeExit> time_holder;
|
||||
return time_holder && R_SUCCEEDED(timeGetCurrentTime(TimeType_LocalSystemClock, out));
|
||||
}
|
||||
}
|
||||
|
||||
UartPortService::UartPortService(const sm::MitmProcessInfo &cl, std::unique_ptr<::UartPortSession> s) : m_client_info(cl), m_srv(std::move(s)) {
|
||||
Result rc=0;
|
||||
/* Get a timestamp. */
|
||||
u64 timestamp0=0, timestamp1;
|
||||
this->TryGetCurrentTimestamp(×tamp0);
|
||||
timestamp1 = armGetSystemTick();
|
||||
|
||||
/* Setup the btsnoop base timestamps. */
|
||||
this->m_timestamp_base = timestamp0;
|
||||
if (this->m_timestamp_base) {
|
||||
this->m_timestamp_base = 0x00E03AB44A676000 + (this->m_timestamp_base - 946684800) * 1000000;
|
||||
}
|
||||
this->m_tick_base = timestamp1;
|
||||
|
||||
/* Setup/create the logging directory. */
|
||||
std::snprintf(this->m_base_path, sizeof(this->m_base_path), "uart_logs/%011lu_%011lu_%016lx", timestamp0, timestamp1, static_cast<u64>(this->m_client_info.program_id));
|
||||
ams::mitm::fs::CreateAtmosphereSdDirectory("uart_logs");
|
||||
ams::mitm::fs::CreateAtmosphereSdDirectory(this->m_base_path);
|
||||
|
||||
/* Create/initialize the text cmd_log. */
|
||||
char tmp_path[256];
|
||||
std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->m_base_path, "cmd_log");
|
||||
ams::mitm::fs::CreateAtmosphereSdFile(tmp_path, 0, 0);
|
||||
this->m_cmdlog_pos = 0;
|
||||
|
||||
/* Initialize the Send cache-buffer. */
|
||||
this->m_send_cache_buffer = static_cast<u8 *>(std::malloc(this->CacheBufferSize));
|
||||
AMS_ABORT_UNLESS(this->m_send_cache_buffer != nullptr);
|
||||
std::memset(this->m_send_cache_buffer, 0, this->CacheBufferSize);
|
||||
this->m_send_cache_pos = 0;
|
||||
|
||||
/* Initialize the Receive cache-buffer. */
|
||||
this->m_receive_cache_buffer = static_cast<u8 *>(std::malloc(this->CacheBufferSize));
|
||||
AMS_ABORT_UNLESS(this->m_receive_cache_buffer != nullptr);
|
||||
std::memset(this->m_receive_cache_buffer, 0, this->CacheBufferSize);
|
||||
this->m_receive_cache_pos = 0;
|
||||
|
||||
/* Initialize the datalog. */
|
||||
std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->m_base_path, "btsnoop_hci.log");
|
||||
ams::mitm::fs::CreateAtmosphereSdFile(tmp_path, 0, 0);
|
||||
rc = ams::mitm::fs::OpenAtmosphereSdFile(&this->m_datalog_file, tmp_path, FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
|
||||
/* Set datalog_ready to whether initialization was successful. */
|
||||
this->m_datalog_ready = R_SUCCEEDED(rc);
|
||||
|
||||
if (this->m_datalog_ready) {
|
||||
std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
|
||||
logger->InitializeDataLog(&this->m_datalog_file, &this->m_datalog_pos);
|
||||
}
|
||||
|
||||
/* This will be enabled by WriteUartData once a certain command is detected. */
|
||||
/* If you want to log all HCI traffic during system-boot initialization, you can change this field to true. */
|
||||
/* When changed to true, qlaunch will hang at a black-screen during system-boot, due to the bluetooth slowdown. */
|
||||
this->m_data_logging_enabled = false;
|
||||
}
|
||||
|
||||
/* Append the specified string to the text cmd_log file. */
|
||||
void UartPortService::WriteCmdLog(const char *str) {
|
||||
char tmp_path[256];
|
||||
std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->m_base_path, "cmd_log");
|
||||
std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
|
||||
logger->SendTextLogData(tmp_path, &this->m_cmdlog_pos, str);
|
||||
}
|
||||
|
||||
/* Log data from Send/Receive. */
|
||||
/* dir: false = Send (host->controller), true = Receive (controller->host). */
|
||||
void UartPortService::WriteUartData(bool dir, const void* buffer, size_t size) {
|
||||
/* Select which cache buffer/pos to use via dir. */
|
||||
u8 *cache_buffer = !dir ? this->m_send_cache_buffer : this->m_receive_cache_buffer;
|
||||
size_t *cache_pos = !dir ? &this->m_send_cache_pos : &this->m_receive_cache_pos;
|
||||
|
||||
/* Verify that the input size is non-zero, and within cache buffer bounds. */
|
||||
if (size && *cache_pos + size <= this->CacheBufferSize) {
|
||||
struct {
|
||||
u8 opcode[0x2];
|
||||
u8 param_len;
|
||||
} *hci_cmd = reinterpret_cast<decltype(hci_cmd)>(&cache_buffer[0x1]);
|
||||
static_assert(sizeof(*hci_cmd) == 0x3);
|
||||
|
||||
struct {
|
||||
u8 handle_flags[0x2];
|
||||
u16 data_len;
|
||||
} *hci_acl_data = reinterpret_cast<decltype(hci_acl_data)>(&cache_buffer[0x1]);
|
||||
static_assert(sizeof(*hci_acl_data) == 0x4);
|
||||
|
||||
struct {
|
||||
u8 handle_flags[0x2];
|
||||
u8 data_len;
|
||||
} *hci_sco_data = reinterpret_cast<decltype(hci_sco_data)>(&cache_buffer[0x1]);
|
||||
static_assert(sizeof(*hci_sco_data) == 0x3);
|
||||
|
||||
struct {
|
||||
u8 event_code;
|
||||
u8 param_len;
|
||||
} *hci_event = reinterpret_cast<decltype(hci_event)>(&cache_buffer[0x1]);
|
||||
static_assert(sizeof(*hci_event) == 0x2);
|
||||
|
||||
struct {
|
||||
u8 handle_flags[0x2];
|
||||
u16 data_load_len : 14;
|
||||
u8 rfu1 : 2;
|
||||
} *hci_iso_data = reinterpret_cast<decltype(hci_iso_data)>(&cache_buffer[0x1]);
|
||||
static_assert(sizeof(*hci_iso_data) == 0x4);
|
||||
|
||||
/* Copy the input data into the cache and update the pos. */
|
||||
std::memcpy(&cache_buffer[*cache_pos], buffer, size);
|
||||
(*cache_pos)+= size;
|
||||
|
||||
/* Process the packets in the cache. */
|
||||
do {
|
||||
size_t orig_pkt_len = 0x0;
|
||||
size_t pkt_len = 0x1;
|
||||
|
||||
/* Determine which HCI packet this is, via the packet indicator. */
|
||||
/* These are supported regardless of whether the official bluetooth-sysmodule supports it. */
|
||||
|
||||
if (cache_buffer[0] == 0x1) { /* HCI Command */
|
||||
if (*cache_pos >= 0x1+sizeof(*hci_cmd)) {
|
||||
orig_pkt_len = sizeof(*hci_cmd) + hci_cmd->param_len;
|
||||
/* Check for the first command used in the port which is opened last by bluetooth-sysmodule. */
|
||||
/* This is a vendor command. */
|
||||
/* Once detected, data-logging will be enabled. */
|
||||
if (!this->m_data_logging_enabled && hci_cmd->opcode[1] == 0xFC && hci_cmd->opcode[0] == 0x16) {
|
||||
this->m_data_logging_enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cache_buffer[0] == 0x2) { /* HCI ACL Data */
|
||||
if (*cache_pos >= 0x1+sizeof(*hci_acl_data)) {
|
||||
orig_pkt_len = sizeof(*hci_acl_data) + hci_acl_data->data_len;
|
||||
}
|
||||
}
|
||||
else if (cache_buffer[0] == 0x3) { /* HCI Synchronous Data (SCO) */
|
||||
if (*cache_pos >= 0x1+sizeof(*hci_sco_data)) {
|
||||
orig_pkt_len = sizeof(*hci_sco_data) + hci_sco_data->data_len;
|
||||
}
|
||||
}
|
||||
else if (cache_buffer[0] == 0x4) { /* HCI Event */
|
||||
if (*cache_pos >= 0x1+sizeof(*hci_event)) {
|
||||
orig_pkt_len = sizeof(*hci_event) + hci_event->param_len;
|
||||
}
|
||||
}
|
||||
else if (cache_buffer[0] == 0x5) { /* HCI ISO Data */
|
||||
if (*cache_pos >= 0x1+sizeof(*hci_iso_data)) {
|
||||
orig_pkt_len = sizeof(*hci_iso_data) + hci_iso_data->data_load_len;
|
||||
}
|
||||
}
|
||||
else { /* Unknown HCI packet */
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "WriteUartData(dir = %s): Unknown HCI packet indicator 0x%x, ignoring the packet and emptying the cache.\n", !dir ? "send" : "receive", cache_buffer[0]);
|
||||
this->WriteCmdLog(str);
|
||||
*cache_pos = 0;
|
||||
}
|
||||
|
||||
/* If a full packet is available in the cache, update pkt_len. */
|
||||
if (orig_pkt_len) {
|
||||
if (*cache_pos >= 0x1+orig_pkt_len) {
|
||||
pkt_len+= orig_pkt_len;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a packet is available, log it and update the cache. */
|
||||
if (pkt_len>0x1) {
|
||||
/* Only write to the file if data-logging is enabled and initialized. */
|
||||
if (this->m_data_logging_enabled && this->m_datalog_ready) {
|
||||
std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
|
||||
if (!logger->SendLogData(&this->m_datalog_file, &this->m_datalog_pos, this->m_timestamp_base, this->m_tick_base, dir, cache_buffer, pkt_len)) {
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "WriteUartData(): SendLogData dropped packet with size = 0x%lx\n", pkt_len);
|
||||
this->WriteCmdLog(str);
|
||||
}
|
||||
}
|
||||
(*cache_pos)-= pkt_len;
|
||||
if (*cache_pos) {
|
||||
std::memmove(cache_buffer, &cache_buffer[pkt_len], *cache_pos);
|
||||
}
|
||||
}
|
||||
/* Otherwise, exit the loop. */
|
||||
else break;
|
||||
} while(*cache_pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward OpenPort and write to the cmd_log. */
|
||||
Result UartPortService::OpenPort(sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length) {
|
||||
Result rc = uartPortSessionOpenPortFwd(this->m_srv.get(), reinterpret_cast<bool *>(out.GetPointer()), port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle.GetValue(), receive_handle.GetValue(), send_buffer_length, receive_buffer_length);
|
||||
svcCloseHandle(send_handle.GetValue());
|
||||
svcCloseHandle(receive_handle.GetValue());
|
||||
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "OpenPort(port = 0x%x, baud_rate = %u, flow_control_mode = %u, device_variation = %u, is_invert_tx = %d, is_invert_rx = %d, is_invert_rts = %d, is_invert_cts = %d, send_buffer_length = 0x%lx, receive_buffer_length = 0x%lx): rc = 0x%x, out = %d\n", port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_buffer_length, receive_buffer_length, rc.GetValue(), out.GetValue());
|
||||
this->WriteCmdLog(str);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward OpenPortForDev and write to the cmd_log. */
|
||||
Result UartPortService::OpenPortForDev(sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length) {
|
||||
Result rc = uartPortSessionOpenPortForDevFwd(this->m_srv.get(), reinterpret_cast<bool *>(out.GetPointer()), port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle.GetValue(), receive_handle.GetValue(), send_buffer_length, receive_buffer_length);
|
||||
svcCloseHandle(send_handle.GetValue());
|
||||
svcCloseHandle(receive_handle.GetValue());
|
||||
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "OpenPortForDev(port = 0x%x, baud_rate = %u, flow_control_mode = %u, device_variation = %u, is_invert_tx = %d, is_invert_rx = %d, is_invert_rts = %d, is_invert_cts = %d, send_buffer_length = 0x%lx, receive_buffer_length = 0x%lx): rc = 0x%x, out = %d\n", port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_buffer_length, receive_buffer_length, rc.GetValue(), out.GetValue());
|
||||
this->WriteCmdLog(str);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward GetWritableLength and write to the cmd_log. */
|
||||
Result UartPortService::GetWritableLength(sf::Out<u64> out) {
|
||||
Result rc = uartPortSessionGetWritableLength(this->m_srv.get(), reinterpret_cast<u64 *>(out.GetPointer()));
|
||||
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "GetWritableLength(): rc = 0x%x, out = 0x%lx\n", rc.GetValue(), out.GetValue());
|
||||
this->WriteCmdLog(str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward Send and log the data if the out_size is non-zero. */
|
||||
Result UartPortService::Send(sf::Out<u64> out_size, const sf::InAutoSelectBuffer &data) {
|
||||
Result rc = uartPortSessionSend(this->m_srv.get(), data.GetPointer(), data.GetSize(), reinterpret_cast<u64 *>(out_size.GetPointer()));
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_size.GetValue()) {
|
||||
this->WriteUartData(false, data.GetPointer(), out_size.GetValue());
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward GetReadableLength and write to the cmd_log. */
|
||||
Result UartPortService::GetReadableLength(sf::Out<u64> out) {
|
||||
Result rc = uartPortSessionGetReadableLength(this->m_srv.get(), reinterpret_cast<u64 *>(out.GetPointer()));
|
||||
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "GetReadableLength(): rc = 0x%x, out = 0x%lx\n", rc.GetValue(), out.GetValue());
|
||||
this->WriteCmdLog(str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward Receive and log the data if the out_size is non-zero. */
|
||||
Result UartPortService::Receive(sf::Out<u64> out_size, const sf::OutAutoSelectBuffer &data) {
|
||||
Result rc = uartPortSessionReceive(this->m_srv.get(), data.GetPointer(), data.GetSize(), reinterpret_cast<u64 *>(out_size.GetPointer()));
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_size.GetValue()) {
|
||||
this->WriteUartData(true, data.GetPointer(), out_size.GetValue());
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward BindPortEvent and write to the cmd_log. */
|
||||
Result UartPortService::BindPortEvent(sf::Out<bool> out, sf::OutCopyHandle out_event_handle, UartPortEventType port_event_type, s64 threshold) {
|
||||
Result rc = uartPortSessionBindPortEventFwd(this->m_srv.get(), port_event_type, threshold, reinterpret_cast<bool *>(out.GetPointer()), out_event_handle.GetHandlePointer());
|
||||
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "BindPortEvent(port_event_type = 0x%x, threshold = 0x%lx): rc = 0x%x, out = %d\n", port_event_type, threshold, rc.GetValue(), out.GetValue());
|
||||
this->WriteCmdLog(str);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Forward UnbindPortEvent and write to the cmd_log. */
|
||||
Result UartPortService::UnbindPortEvent(sf::Out<bool> out, UartPortEventType port_event_type) {
|
||||
Result rc = uartPortSessionUnbindPortEvent(this->m_srv.get(), port_event_type, reinterpret_cast<bool *>(out.GetPointer()));
|
||||
|
||||
char str[256];
|
||||
std::snprintf(str, sizeof(str), "UnbindPortEvent(port_event_type = 0x%x): rc = 0x%x, out = %d\n", port_event_type, rc.GetValue(), out.GetValue());
|
||||
this->WriteCmdLog(str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result UartMitmService::CreatePortSession(sf::Out<sf::SharedPointer<impl::IPortSession>> out) {
|
||||
/* Open a port interface. */
|
||||
UartPortSession port;
|
||||
R_TRY(uartCreatePortSessionFwd(this->forward_service.get(), &port));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&port.s)};
|
||||
|
||||
out.SetValue(sf::CreateSharedObjectEmplaced<impl::IPortSession, UartPortService>(this->client_info, std::make_unique<UartPortSession>(port)), target_object_id);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
108
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.hpp
Normal file
108
stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.hpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "uart_mitm_logger.hpp"
|
||||
#include "uart_shim.h"
|
||||
|
||||
#define AMS_UART_IPORTSESSION_MITM_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenPort, (sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length), (out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle, receive_handle, send_buffer_length, receive_buffer_length)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, OpenPortForDev, (sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length), (out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle, receive_handle, send_buffer_length, receive_buffer_length)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, GetWritableLength, (sf::Out<u64> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, Send, (sf::Out<u64> out_size, const sf::InAutoSelectBuffer &data), (out_size, data)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetReadableLength, (sf::Out<u64> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 5, Result, Receive, (sf::Out<u64> out_size, const sf::OutAutoSelectBuffer &data), (out_size, data)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, BindPortEvent, (sf::Out<bool> out, sf::OutCopyHandle out_event_handle, UartPortEventType port_event_type, s64 threshold), (out, out_event_handle, port_event_type, threshold)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 7, Result, UnbindPortEvent, (sf::Out<bool> out, UartPortEventType port_event_type), (out, port_event_type))
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::mitm::uart::impl, IPortSession, AMS_UART_IPORTSESSION_MITM_INTERFACE_INFO)
|
||||
|
||||
#define AMS_UART_MITM_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, CreatePortSession, (sf::Out<sf::SharedPointer<::ams::mitm::uart::impl::IPortSession>> out), (out))
|
||||
|
||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::uart::impl, IUartMitmInterface, AMS_UART_MITM_INTERFACE_INFO)
|
||||
|
||||
namespace ams::mitm::uart {
|
||||
|
||||
class UartPortService {
|
||||
private:
|
||||
sm::MitmProcessInfo m_client_info;
|
||||
std::unique_ptr<::UartPortSession> m_srv;
|
||||
|
||||
static constexpr inline size_t CacheBufferSize = 0x1000;
|
||||
|
||||
s64 m_timestamp_base;
|
||||
s64 m_tick_base;
|
||||
|
||||
char m_base_path[256];
|
||||
|
||||
size_t m_cmdlog_pos;
|
||||
size_t m_datalog_pos;
|
||||
|
||||
bool m_datalog_ready;
|
||||
bool m_data_logging_enabled;
|
||||
|
||||
FsFile m_datalog_file;
|
||||
|
||||
u8 *m_send_cache_buffer;
|
||||
u8 *m_receive_cache_buffer;
|
||||
size_t m_send_cache_pos;
|
||||
size_t m_receive_cache_pos;
|
||||
|
||||
bool TryGetCurrentTimestamp(u64 *out);
|
||||
void WriteCmdLog(const char *str);
|
||||
void WriteUartData(bool dir, const void* buffer, size_t size);
|
||||
public:
|
||||
UartPortService(const sm::MitmProcessInfo &cl, std::unique_ptr<::UartPortSession> s);
|
||||
|
||||
virtual ~UartPortService() {
|
||||
std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
|
||||
logger->WaitFinished();
|
||||
uartPortSessionClose(this->m_srv.get());
|
||||
fsFileClose(&this->m_datalog_file);
|
||||
std::free(this->m_send_cache_buffer);
|
||||
std::free(this->m_receive_cache_buffer);
|
||||
}
|
||||
public:
|
||||
/* Actual command API. */
|
||||
Result OpenPort(sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length);
|
||||
Result OpenPortForDev(sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length);
|
||||
Result GetWritableLength(sf::Out<u64> out);
|
||||
Result Send(sf::Out<u64> out_size, const sf::InAutoSelectBuffer &data);
|
||||
Result GetReadableLength(sf::Out<u64> out);
|
||||
Result Receive(sf::Out<u64> out_size, const sf::OutAutoSelectBuffer &data);
|
||||
Result BindPortEvent(sf::Out<bool> out, sf::OutCopyHandle out_event_handle, UartPortEventType port_event_type, s64 threshold);
|
||||
Result UnbindPortEvent(sf::Out<bool> out, UartPortEventType port_event_type);
|
||||
};
|
||||
static_assert(impl::IsIPortSession<UartPortService>);
|
||||
|
||||
class UartMitmService : public sf::MitmServiceImplBase {
|
||||
public:
|
||||
using MitmServiceImplBase::MitmServiceImplBase;
|
||||
public:
|
||||
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
|
||||
/* We will mitm:
|
||||
* - bluetooth, for logging HCI.
|
||||
*/
|
||||
return client_info.program_id == ncm::SystemProgramId::Bluetooth;
|
||||
}
|
||||
public:
|
||||
Result CreatePortSession(sf::Out<sf::SharedPointer<impl::IPortSession>> out);
|
||||
};
|
||||
static_assert(impl::IsIUartMitmInterface<UartMitmService>);
|
||||
|
||||
}
|
77
stratosphere/ams_mitm/source/uart_mitm/uart_shim.c
Normal file
77
stratosphere/ams_mitm/source/uart_mitm/uart_shim.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
#include "uart_shim.h"
|
||||
|
||||
/* Command forwarders. */
|
||||
Result uartCreatePortSessionFwd(Service* s, UartPortSession* out) {
|
||||
return serviceDispatch(s, 6,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s,
|
||||
);
|
||||
}
|
||||
|
||||
// [7.0.0+]
|
||||
static Result _uartPortSessionOpenPortFwd(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length, u32 cmd_id) {
|
||||
const struct {
|
||||
u8 is_invert_tx;
|
||||
u8 is_invert_rx;
|
||||
u8 is_invert_rts;
|
||||
u8 is_invert_cts;
|
||||
u32 port;
|
||||
u32 baud_rate;
|
||||
u32 flow_control_mode;
|
||||
u32 device_variation;
|
||||
u32 pad;
|
||||
u64 send_buffer_length;
|
||||
u64 receive_buffer_length;
|
||||
} in = { is_invert_tx!=0, is_invert_rx!=0, is_invert_rts!=0, is_invert_cts!=0, port, baud_rate, flow_control_mode, device_variation, 0, send_buffer_length, receive_buffer_length };
|
||||
|
||||
u8 tmp=0;
|
||||
Result rc = serviceDispatchInOut(&s->s, cmd_id, in, tmp,
|
||||
.in_num_handles = 2,
|
||||
.in_handles = { send_handle, receive_handle },
|
||||
);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result uartPortSessionOpenPortFwd(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length) {
|
||||
return _uartPortSessionOpenPortFwd(s, out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle, receive_handle, send_buffer_length, receive_buffer_length, 0);
|
||||
}
|
||||
|
||||
Result uartPortSessionOpenPortForDevFwd(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length) {
|
||||
return _uartPortSessionOpenPortFwd(s, out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle, receive_handle, send_buffer_length, receive_buffer_length, 1);
|
||||
}
|
||||
|
||||
Result uartPortSessionBindPortEventFwd(UartPortSession* s, UartPortEventType port_event_type, s64 threshold, bool *out, Handle *handle_out) {
|
||||
const struct {
|
||||
u32 port_event_type;
|
||||
u32 pad;
|
||||
u64 threshold;
|
||||
} in = { port_event_type, 0, threshold };
|
||||
|
||||
u8 tmp=0;
|
||||
Result rc = serviceDispatchInOut(&s->s, 6, in, tmp,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = handle_out,
|
||||
);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
return rc;
|
||||
}
|
||||
|
23
stratosphere/ams_mitm/source/uart_mitm/uart_shim.h
Normal file
23
stratosphere/ams_mitm/source/uart_mitm/uart_shim.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* @file uart_shim.h
|
||||
* @brief UART IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Command forwarders. */
|
||||
Result uartCreatePortSessionFwd(Service* s, UartPortSession* out);
|
||||
|
||||
Result uartPortSessionOpenPortFwd(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length);
|
||||
Result uartPortSessionOpenPortForDevFwd(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length);
|
||||
Result uartPortSessionBindPortEventFwd(UartPortSession* s, UartPortEventType port_event_type, s64 threshold, bool *out, Handle *handle_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
96
stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.cpp
Normal file
96
stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "../amsmitm_initialization.hpp"
|
||||
#include "uartmitm_module.hpp"
|
||||
#include "uart_mitm_service.hpp"
|
||||
#include "uart_mitm_logger.hpp"
|
||||
|
||||
namespace ams::mitm::uart {
|
||||
|
||||
namespace {
|
||||
|
||||
enum PortIndex {
|
||||
PortIndex_Mitm,
|
||||
PortIndex_Count,
|
||||
};
|
||||
|
||||
constexpr sm::ServiceName UartMitmServiceName = sm::ServiceName::Encode("uart");
|
||||
|
||||
struct ServerOptions {
|
||||
static constexpr size_t PointerBufferSize = 0x1000;
|
||||
static constexpr size_t MaxDomains = 0;
|
||||
static constexpr size_t MaxDomainObjects = 0;
|
||||
};
|
||||
|
||||
constexpr size_t MaxServers = 1;
|
||||
constexpr size_t MaxSessions = 10;
|
||||
|
||||
class ServerManager final : public sf::hipc::ServerManager<MaxServers, ServerOptions, MaxSessions> {
|
||||
private:
|
||||
virtual Result OnNeedsToAccept(int port_index, Server *server) override;
|
||||
};
|
||||
|
||||
ServerManager g_server_manager;
|
||||
|
||||
Result ServerManager::OnNeedsToAccept(int port_index, Server *server) {
|
||||
/* Acknowledge the mitm session. */
|
||||
std::shared_ptr<::Service> fsrv;
|
||||
sm::MitmProcessInfo client_info;
|
||||
server->AcknowledgeMitmSession(std::addressof(fsrv), std::addressof(client_info));
|
||||
|
||||
switch (port_index) {
|
||||
case PortIndex_Mitm:
|
||||
return this->AcceptMitmImpl(server, sf::CreateSharedObjectEmplaced<impl::IUartMitmInterface, UartMitmService>(decltype(fsrv)(fsrv), client_info), fsrv);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldMitmUart() {
|
||||
u8 en = 0;
|
||||
if (settings::fwdbg::GetSettingsItemValue(&en, sizeof(en), "atmosphere", "enable_uart_mitm") == sizeof(en)) {
|
||||
return (en != 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void MitmModule::ThreadFunction(void *arg) {
|
||||
/* The OpenPort cmds had the params changed with 6.x/7.x, so only support 7.x+. */
|
||||
if (hos::GetVersion() < hos::Version_7_0_0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait until initialization is complete. */
|
||||
mitm::WaitInitialized();
|
||||
|
||||
/* Only use uart-mitm if enabled by the sys-setting. */
|
||||
if (!ShouldMitmUart()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create mitm servers. */
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<UartMitmService>(PortIndex_Mitm, UartMitmServiceName)));
|
||||
|
||||
mitm::uart::g_logger = std::make_shared<UartLogger>();
|
||||
|
||||
/* Loop forever, servicing our services. */
|
||||
g_server_manager.LoopProcess();
|
||||
|
||||
mitm::uart::g_logger.reset();
|
||||
}
|
||||
|
||||
}
|
24
stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.hpp
Normal file
24
stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "../amsmitm_module.hpp"
|
||||
|
||||
namespace ams::mitm::uart {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x4000, AMS_GET_SYSTEM_THREAD_PRIORITY(uart, IpcServer) - 1);
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue