use crate::{
ndisapi::{self, FilterFlags},
IntermediateBuffer,
};
use futures::StreamExt;
use std::sync::Arc;
use windows::{
core::Result,
Win32::{
Foundation::{HANDLE, WIN32_ERROR},
System::Threading::CreateEventW,
},
};
use self::win32_event_stream::Win32EventStream;
mod win32_event_stream;
pub struct AsyncNdisapiAdapter {
driver: Arc<ndisapi::Ndisapi>,
adapter_handle: HANDLE,
notif: Win32EventStream,
}
impl AsyncNdisapiAdapter {
pub fn new(
driver: Arc<ndisapi::Ndisapi>, adapter_handle: HANDLE, ) -> Result<Self> {
let event_handle = unsafe {
CreateEventW(None, true, false, None)?
};
driver.set_packet_event(adapter_handle, event_handle)?;
Ok(Self {
adapter_handle,
driver,
notif: Win32EventStream::new(event_handle)?, })
}
pub fn set_adapter_mode(&self, flags: FilterFlags) -> Result<()> {
self.driver.set_adapter_mode(self.adapter_handle, flags)?;
Ok(())
}
pub async fn read_packet(&mut self, packet: &mut IntermediateBuffer) -> Result<()> {
let driver = self.driver.clone();
let mut request = ndisapi::EthRequestMut::new(self.adapter_handle);
request.set_packet(packet);
if driver.read_packet(&mut request).is_ok() {
return Ok(());
}
match self.notif.next().await {
Some(result) => match result {
Ok(_) => match driver.read_packet(&mut request) {
Ok(_) => Ok(()),
Err(e) => Err(e),
},
Err(e) => Err(e),
},
None => {
Err(WIN32_ERROR(0u32).into())
}
}
}
pub async fn read_packets<'a, const N: usize>(
&mut self,
packets: impl IntoIterator<Item = &'a mut IntermediateBuffer>,
) -> Result<usize> {
let driver = self.driver.clone();
let mut request =
ndisapi::EthMRequestMut::<N>::from_iter(self.adapter_handle, packets.into_iter());
if driver.read_packets(&mut request).is_ok() {
return Ok(request.get_packet_success() as usize);
}
match self.notif.next().await {
Some(result) => match result {
Ok(_) => match driver.read_packets(&mut request) {
Ok(_) => Ok(request.get_packet_success() as usize),
Err(err) => Err(err),
},
Err(e) => Err(e),
},
None => {
Err(WIN32_ERROR(0u32).into())
}
}
}
pub fn send_packet_to_adapter(&self, packet: &mut IntermediateBuffer) -> Result<()> {
let mut request = ndisapi::EthRequest::new(self.adapter_handle);
request.set_packet(packet);
self.driver.send_packet_to_adapter(&request)
}
pub fn send_packets_to_adapter<'a, const N: usize>(
&mut self,
packets: impl IntoIterator<Item = &'a IntermediateBuffer>,
) -> Result<usize> {
let request =
ndisapi::EthMRequest::<N>::from_iter(self.adapter_handle, packets.into_iter());
match self.driver.send_packets_to_adapter(&request) {
Ok(_) => Ok(request.get_packet_success() as usize),
Err(err) => Err(err),
}
}
pub fn send_packet_to_mstcp(&self, packet: &IntermediateBuffer) -> Result<()> {
let mut request = ndisapi::EthRequest::new(self.adapter_handle);
request.set_packet(packet);
self.driver.send_packet_to_mstcp(&request)
}
pub fn send_packets_to_mstcp<'a, const N: usize>(
&mut self,
packets: impl IntoIterator<Item = &'a IntermediateBuffer>,
) -> Result<usize> {
let request =
ndisapi::EthMRequest::<N>::from_iter(self.adapter_handle, packets.into_iter());
match self.driver.send_packets_to_mstcp(&request) {
Ok(_) => Ok(request.get_packet_success() as usize),
Err(err) => Err(err),
}
}
}
impl Drop for AsyncNdisapiAdapter {
fn drop(&mut self) {
_ = self
.driver
.set_adapter_mode(self.adapter_handle, FilterFlags::from_bits_truncate(0));
_ = self
.driver
.set_packet_event(self.adapter_handle, HANDLE(std::ptr::null_mut()));
}
}