Files
vnt/vnt/tun/src/windows/ffi.rs
T

503 lines
14 KiB
Rust

// Many things will be used in the future
#![allow(unused)]
//! Module holding safe wrappers over winapi functions
use winapi::shared::basetsd::*;
use winapi::shared::guiddef::GUID;
use winapi::shared::ifdef::*;
use winapi::shared::minwindef::*;
use winapi::shared::netioapi::*;
use winapi::shared::winerror::*;
use winapi::um::combaseapi::*;
use winapi::um::errhandlingapi::*;
use winapi::um::fileapi::*;
use winapi::um::handleapi::*;
use winapi::um::ioapiset::*;
use winapi::um::setupapi::*;
use winapi::um::synchapi::*;
use winapi::um::winioctl::*;
use winapi::um::winnt::*;
use winapi::um::winreg::*;
use std::error::Error;
use std::{io, mem, ptr};
use winapi::um::minwinbase::OVERLAPPED_u;
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[repr(C)]
#[derive(Clone, Copy)]
/// Custom type to handle variable size SP_DRVINFO_DETAIL_DATA_W
pub struct SP_DRVINFO_DETAIL_DATA_W2 {
pub cbSize: DWORD,
pub InfDate: FILETIME,
pub CompatIDsOffset: DWORD,
pub CompatIDsLength: DWORD,
pub Reserved: ULONG_PTR,
pub SectionName: [WCHAR; 256],
pub InfFileName: [WCHAR; 260],
pub DrvDescription: [WCHAR; 256],
pub HardwareID: [WCHAR; 512],
}
pub fn string_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
// GUID_STRING_CHARACTERS + 1
let mut string = vec![0; 39];
match unsafe { StringFromGUID2(guid, string.as_mut_ptr(), string.len() as _) } {
0 => Err(io::Error::new(io::ErrorKind::Other, "Insufficent buffer")),
_ => Ok(string),
}
}
pub fn alias_to_luid(alias: &[WCHAR]) -> io::Result<NET_LUID> {
let mut luid = unsafe { mem::zeroed() };
match unsafe { ConvertInterfaceAliasToLuid(alias.as_ptr(), &mut luid) } {
0 => Ok(luid),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_index(luid: &NET_LUID) -> io::Result<NET_IFINDEX> {
let mut index = 0;
match unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) } {
0 => Ok(index),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_guid(luid: &NET_LUID) -> io::Result<GUID> {
let mut guid = unsafe { mem::zeroed() };
match unsafe { ConvertInterfaceLuidToGuid(luid, &mut guid) } {
0 => Ok(guid),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_alias(luid: &NET_LUID) -> io::Result<Vec<WCHAR>> {
// IF_MAX_STRING_SIZE + 1
let mut alias = vec![0; 257];
match unsafe { ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len()) } {
0 => Ok(alias),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn close_handle(handle: HANDLE) -> io::Result<()> {
match unsafe { CloseHandle(handle) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn create_file(
file_name: &[WCHAR],
desired_access: DWORD,
share_mode: DWORD,
creation_disposition: DWORD,
flags_and_attributes: DWORD,
) -> io::Result<HANDLE> {
match unsafe {
CreateFileW(
file_name.as_ptr(),
desired_access,
share_mode,
ptr::null_mut(),
creation_disposition,
flags_and_attributes,
ptr::null_mut(),
)
} {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
handle => Ok(handle),
}
}
pub fn read_file(handle: HANDLE, buffer: &mut [u8]) -> io::Result<DWORD> {
let mut ret = 0;
//https://www.cnblogs.com/linyilong3/archive/2012/05/03/2480451.html
unsafe {
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
Internal: 0,
InternalHigh: 0,
u: Default::default(),
hEvent: ptr::null_mut(),
};
if 0 == ReadFile(
handle,
buffer.as_mut_ptr() as _,
buffer.len() as _,
&mut ret,
&mut ip_overlapped,
) {
let e = io::Error::last_os_error();
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
return Err(e);
}
} else {
return Err(e);
}
}
Ok(ret)
}
}
pub fn write_file(handle: HANDLE, buffer: &[u8]) -> io::Result<DWORD> {
let mut ret = 0;
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
Internal: 0,
InternalHigh: 0,
u: Default::default(),
hEvent: ptr::null_mut(),
};
unsafe {
if 0 == WriteFile(
handle,
buffer.as_ptr() as _,
buffer.len() as _,
&mut ret,
&mut ip_overlapped,
) {
let e = io::Error::last_os_error();
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
return Err(e);
}
} else {
return Err(e);
}
}
Ok(ret)
}
}
pub fn create_device_info_list(guid: &GUID) -> io::Result<HDEVINFO> {
match unsafe { SetupDiCreateDeviceInfoList(guid, ptr::null_mut()) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
devinfo => Ok(devinfo),
}
}
pub fn get_class_devs(guid: &GUID, flags: DWORD) -> io::Result<HDEVINFO> {
match unsafe { SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), flags) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
devinfo => Ok(devinfo),
}
}
pub fn destroy_device_info_list(devinfo: HDEVINFO) -> io::Result<()> {
match unsafe { SetupDiDestroyDeviceInfoList(devinfo) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn class_name_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
let mut class_name = vec![0; 32];
match unsafe {
SetupDiClassNameFromGuidW(
guid,
class_name.as_mut_ptr(),
class_name.len() as _,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(class_name),
}
}
pub fn create_device_info(
devinfo: HDEVINFO,
device_name: &[WCHAR],
guid: &GUID,
device_description: &[WCHAR],
creation_flags: DWORD,
) -> io::Result<SP_DEVINFO_DATA> {
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
match unsafe {
SetupDiCreateDeviceInfoW(
devinfo,
device_name.as_ptr(),
guid,
device_description.as_ptr(),
ptr::null_mut(),
creation_flags,
&mut devinfo_data,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(devinfo_data),
}
}
pub fn set_selected_device(devinfo: HDEVINFO, devinfo_data: &SP_DEVINFO_DATA) -> io::Result<()> {
match unsafe { SetupDiSetSelectedDevice(devinfo, devinfo_data as *const _ as _) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn set_device_registry_property(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
property: DWORD,
value: &[WCHAR],
) -> io::Result<()> {
match unsafe {
SetupDiSetDeviceRegistryPropertyW(
devinfo,
devinfo_data as *const _ as _,
property,
value.as_ptr() as _,
(value.len() * 2) as _,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn get_device_registry_property(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
property: DWORD,
) -> io::Result<Vec<WCHAR>> {
let mut value = vec![0; 32];
match unsafe {
SetupDiGetDeviceRegistryPropertyW(
devinfo,
devinfo_data as *const _ as _,
property,
ptr::null_mut(),
value.as_mut_ptr() as _,
(value.len() * 2) as _,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(value),
}
}
pub fn build_driver_info_list(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
) -> io::Result<()> {
match unsafe { SetupDiBuildDriverInfoList(devinfo, devinfo_data as *const _ as _, driver_type) }
{
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn destroy_driver_info_list(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
) -> io::Result<()> {
match unsafe {
SetupDiDestroyDriverInfoList(devinfo, devinfo_data as *const _ as _, driver_type)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn get_driver_info_detail(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
drvinfo_data: &SP_DRVINFO_DATA_W,
) -> io::Result<SP_DRVINFO_DETAIL_DATA_W2> {
let mut drvinfo_detail: SP_DRVINFO_DETAIL_DATA_W2 = unsafe { mem::zeroed() };
drvinfo_detail.cbSize = mem::size_of::<SP_DRVINFO_DETAIL_DATA_W>() as _;
match unsafe {
SetupDiGetDriverInfoDetailW(
devinfo,
devinfo_data as *const _ as _,
drvinfo_data as *const _ as _,
&mut drvinfo_detail as *mut _ as _,
mem::size_of_val(&drvinfo_detail) as _,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(drvinfo_detail),
}
}
pub fn set_selected_driver(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
drvinfo_data: &SP_DRVINFO_DATA_W,
) -> io::Result<()> {
match unsafe {
SetupDiSetSelectedDriverW(
devinfo,
devinfo_data as *const _ as _,
drvinfo_data as *const _ as _,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn set_class_install_params(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
params: &impl Copy,
) -> io::Result<()> {
match unsafe {
SetupDiSetClassInstallParamsW(
devinfo,
devinfo_data as *const _ as _,
params as *const _ as _,
mem::size_of_val(params) as _,
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn call_class_installer(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
install_function: DI_FUNCTION,
) -> io::Result<()> {
match unsafe {
SetupDiCallClassInstaller(install_function, devinfo, devinfo_data as *const _ as _)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}
pub fn open_dev_reg_key(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
scope: DWORD,
hw_profile: DWORD,
key_type: DWORD,
sam_desired: REGSAM,
) -> io::Result<HKEY> {
const INVALID_KEY_VALUE: HKEY = INVALID_HANDLE_VALUE as _;
match unsafe {
SetupDiOpenDevRegKey(
devinfo,
devinfo_data as *const _ as _,
scope,
hw_profile,
key_type,
sam_desired,
)
} {
INVALID_KEY_VALUE => Err(io::Error::last_os_error()),
key => Ok(key),
}
}
pub fn notify_change_key_value(
key: HKEY,
watch_subtree: BOOL,
notify_filter: DWORD,
milliseconds: DWORD,
) -> io::Result<()> {
let event = match unsafe { CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null()) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
event => Ok(event),
}?;
match unsafe { RegNotifyChangeKeyValue(key, watch_subtree, notify_filter, event, TRUE) } {
0 => Ok(()),
err => Err(io::Error::from_raw_os_error(err)),
}?;
match unsafe { WaitForSingleObject(event, milliseconds) } {
0 => Ok(()),
0x102 => Err(io::Error::new(
io::ErrorKind::TimedOut,
"Registry timed out",
)),
_ => Err(io::Error::last_os_error()),
}
}
pub fn enum_driver_info(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
member_index: DWORD,
) -> Option<io::Result<SP_DRVINFO_DATA_W>> {
let mut drvinfo_data: SP_DRVINFO_DATA_W = unsafe { mem::zeroed() };
drvinfo_data.cbSize = mem::size_of_val(&drvinfo_data) as _;
match unsafe {
SetupDiEnumDriverInfoW(
devinfo,
devinfo_data as *const _ as _,
driver_type,
member_index,
&mut drvinfo_data,
)
} {
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
0 => Some(Err(io::Error::last_os_error())),
_ => Some(Ok(drvinfo_data)),
}
}
pub fn enum_device_info(
devinfo: HDEVINFO,
member_index: DWORD,
) -> Option<io::Result<SP_DEVINFO_DATA>> {
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
match unsafe { SetupDiEnumDeviceInfo(devinfo, member_index, &mut devinfo_data) } {
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
0 => Some(Err(io::Error::last_os_error())),
_ => Some(Ok(devinfo_data)),
}
}
pub fn device_io_control(
handle: HANDLE,
io_control_code: DWORD,
in_buffer: &impl Copy,
out_buffer: &mut impl Copy,
) -> io::Result<()> {
let mut junk = 0;
match unsafe {
DeviceIoControl(
handle,
io_control_code,
in_buffer as *const _ as _,
mem::size_of_val(in_buffer) as _,
out_buffer as *mut _ as _,
mem::size_of_val(out_buffer) as _,
&mut junk,
ptr::null_mut(),
)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
}