ebpf-for-windows/libs/api_common/device_helper.hpp

135 строки
3.8 KiB
C++

// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#pragma once
#include "ebpf_api.h"
#include "ebpf_tracelog.h"
#include "platform.h"
#define FALSE 0
#define TRUE 1
#include <winioctl.h>
// Device type
#define EBPF_IOCTL_TYPE FILE_DEVICE_NETWORK
// Function codes from 0x800 to 0xFFF are for customer use.
#define IOCTL_EBPF_CTL_METHOD_BUFFERED CTL_CODE(EBPF_IOCTL_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Maximum attempts to invoke an IOCTL.
#define IOCTL_MAX_ATTEMPTS 16
typedef std::vector<uint8_t> ebpf_protocol_buffer_t;
typedef std::vector<uint8_t> ebpf_code_buffer_t;
typedef struct empty_reply
{
} empty_reply_t;
static empty_reply_t _empty_reply;
_Must_inspect_result_ ebpf_result_t
initialize_sync_device_handle();
_Must_inspect_result_ ebpf_result_t
initialize_async_device_handle();
void
clean_up_sync_device_handle();
void
clean_up_async_device_handle();
ebpf_handle_t
get_sync_device_handle();
ebpf_handle_t
get_async_device_handle();
typedef ebpf_result_t (*async_ioctl_completion_callback_t)(_Inout_opt_ void* completion_context);
typedef struct _async_ioctl_completion_context async_ioctl_completion_t;
_Must_inspect_result_ ebpf_result_t
initialize_async_ioctl_operation(
_Inout_opt_ void* callback_context,
_In_ const async_ioctl_completion_callback_t callback,
_Outptr_ async_ioctl_completion_t** async_ioctl_completion);
_Must_inspect_result_ ebpf_result_t
register_wait_async_ioctl_operation(_Inout_ async_ioctl_completion_t* async_ioctl_completion);
void
clean_up_async_ioctl_completion(_Inout_opt_ _Post_invalid_ async_ioctl_completion_t* async_ioctl_completion);
_Ret_notnull_ OVERLAPPED*
get_async_ioctl_operation_overlapped(_In_ const async_ioctl_completion_t* ioctl_completion);
bool
cancel_async_ioctl(_Inout_opt_ OVERLAPPED* overlapped);
_Must_inspect_result_ ebpf_result_t
get_async_ioctl_result(_In_ const async_ioctl_completion_t* ioctl_completion);
template <typename request_t, typename reply_t = empty_reply_t>
uint32_t
invoke_ioctl(request_t& request, reply_t& reply = _empty_reply, _Inout_opt_ OVERLAPPED* overlapped = nullptr)
{
uint32_t return_value = ERROR_SUCCESS;
uint32_t actual_reply_size;
uint32_t request_size;
void* request_ptr;
uint32_t reply_size;
void* reply_ptr;
bool variable_reply_size = false;
if constexpr (std::is_same<request_t, nullptr_t>::value) {
request_size = 0;
request_ptr = nullptr;
} else if constexpr (std::is_same<request_t, ebpf_protocol_buffer_t>::value) {
request_size = static_cast<uint32_t>(request.size());
request_ptr = request.data();
} else {
request_size = sizeof(request);
request_ptr = &request;
}
if constexpr (std::is_same<reply_t, nullptr_t>::value) {
reply_size = 0;
reply_ptr = nullptr;
} else if constexpr (std::is_same<reply_t, ebpf_protocol_buffer_t>::value) {
reply_size = static_cast<uint32_t>(reply.size());
reply_ptr = reply.data();
variable_reply_size = true;
} else if constexpr (std::is_same<reply_t, empty_reply>::value) {
reply_size = 0;
reply_ptr = nullptr;
} else {
reply_size = static_cast<uint32_t>(sizeof(reply));
reply_ptr = &reply;
}
auto success = Platform::DeviceIoControl(
overlapped ? get_async_device_handle() : get_sync_device_handle(),
IOCTL_EBPF_CTL_METHOD_BUFFERED,
request_ptr,
request_size,
reply_ptr,
reply_size,
&actual_reply_size,
overlapped);
if (!success) {
return_value = GetLastError();
EBPF_LOG_WIN32_API_FAILURE(EBPF_TRACELOG_KEYWORD_API, DeviceIoControl);
goto Exit;
}
if (actual_reply_size != reply_size && !variable_reply_size) {
return_value = ERROR_INVALID_PARAMETER;
goto Exit;
}
Exit:
EBPF_RETURN_ERROR(return_value);
}