mirror of
https://github.com/danog/libdvb.git
synced 2024-11-26 20:04:39 +01:00
net refactoring
This commit is contained in:
parent
0b23424405
commit
8fe2424f56
@ -1,43 +1,32 @@
|
|||||||
use {
|
use anyhow::{Context, bail};
|
||||||
std::{
|
|
||||||
path::Path,
|
|
||||||
},
|
|
||||||
|
|
||||||
|
use {
|
||||||
anyhow::Result,
|
anyhow::Result,
|
||||||
|
|
||||||
libdvb::NetDevice,
|
libdvb::NetDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
fn check_net(path: &Path) -> Result<()> {
|
|
||||||
println!("NET: {}", path.display());
|
|
||||||
|
|
||||||
let dev = NetDevice::open(path)?;
|
|
||||||
|
|
||||||
let mut info = libdvb::net::sys::DvbNetIf {
|
|
||||||
pid: 0,
|
|
||||||
if_num: 0,
|
|
||||||
feedtype: libdvb::net::sys::DVB_NET_FEEDTYPE_MPE,
|
|
||||||
};
|
|
||||||
|
|
||||||
dev.add_if(&mut info)?;
|
|
||||||
println!("Interface: {}", dev.get_name());
|
|
||||||
println!("MAC: {}", dev.get_mac());
|
|
||||||
|
|
||||||
dev.remove_if(&info)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let mut args = std::env::args().skip(1);
|
let mut args = std::env::args().skip(1);
|
||||||
if let Some(path) = args.next() {
|
|
||||||
let path = Path::new(&path);
|
let adapter = match args.next() {
|
||||||
check_net(&path)?;
|
Some(v) => v.parse::<u32>().context("adapter number")?,
|
||||||
} else {
|
None => bail!("adapter number not defined"),
|
||||||
eprintln!("path to ca device is not defined");
|
};
|
||||||
}
|
|
||||||
|
let device = match args.next() {
|
||||||
|
Some(v) => v.parse::<u32>().context("device number")?,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let dev = NetDevice::open(adapter, device)?;
|
||||||
|
|
||||||
|
let interface = dev.add_if(0, libdvb::net::sys::DVB_NET_FEEDTYPE_MPE)?;
|
||||||
|
println!("Interface: {}", &interface);
|
||||||
|
let mac = interface.get_mac();
|
||||||
|
println!("MAC: {}", &mac);
|
||||||
|
dev.remove_if(interface)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
136
src/net/mod.rs
136
src/net/mod.rs
@ -3,13 +3,12 @@ pub mod sys;
|
|||||||
|
|
||||||
use {
|
use {
|
||||||
std::{
|
std::{
|
||||||
io::{
|
fmt,
|
||||||
Read,
|
|
||||||
},
|
|
||||||
fs::{
|
fs::{
|
||||||
File,
|
File,
|
||||||
OpenOptions,
|
OpenOptions,
|
||||||
},
|
},
|
||||||
|
io::Read,
|
||||||
os::unix::{
|
os::unix::{
|
||||||
fs::{
|
fs::{
|
||||||
OpenOptionsExt,
|
OpenOptionsExt,
|
||||||
@ -19,7 +18,6 @@ use {
|
|||||||
RawFd,
|
RawFd,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
path::Path,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
anyhow::{
|
anyhow::{
|
||||||
@ -28,17 +26,6 @@ use {
|
|||||||
},
|
},
|
||||||
|
|
||||||
nix::{
|
nix::{
|
||||||
fcntl::{
|
|
||||||
readlink,
|
|
||||||
},
|
|
||||||
sys::{
|
|
||||||
stat::{
|
|
||||||
fstat,
|
|
||||||
major,
|
|
||||||
minor,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
ioctl_readwrite,
|
ioctl_readwrite,
|
||||||
ioctl_write_int_bad,
|
ioctl_write_int_bad,
|
||||||
request_code_none,
|
request_code_none,
|
||||||
@ -49,18 +36,16 @@ use {
|
|||||||
|
|
||||||
|
|
||||||
pub const EMPTY_MAC: &str = "00:00:00:00:00:00";
|
pub const EMPTY_MAC: &str = "00:00:00:00:00:00";
|
||||||
|
const MAC_SIZE: usize = EMPTY_MAC.len();
|
||||||
|
|
||||||
|
|
||||||
/// A reference to the network device
|
/// A reference to the network device
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NetDevice {
|
pub struct NetDevice {
|
||||||
|
adapter: u32,
|
||||||
|
device: u32,
|
||||||
|
|
||||||
file: File,
|
file: File,
|
||||||
|
|
||||||
/// Interface name
|
|
||||||
name: String,
|
|
||||||
|
|
||||||
/// MAC address
|
|
||||||
mac: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -70,86 +55,93 @@ impl AsRawFd for NetDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn read_interface_name<T: AsRawFd>(file: &T) -> Result<String> {
|
|
||||||
let s = fstat(file.as_raw_fd())?;
|
|
||||||
|
|
||||||
let path = format!("/sys/dev/char/{}:{}", major(s.st_rdev), minor(s.st_rdev));
|
|
||||||
let name = readlink(path.as_str())?
|
|
||||||
.to_str()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.rsplit('/')
|
|
||||||
.next()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.split(".net")
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join("_");
|
|
||||||
|
|
||||||
Ok(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn read_mac_address(name: &str) -> Result<String> {
|
|
||||||
ensure!(name.starts_with("dvb"), "incorrect interface name");
|
|
||||||
|
|
||||||
let len = 2 * 6 + 5;
|
|
||||||
|
|
||||||
let mut mac = String::with_capacity(len);
|
|
||||||
let path = format!("/sys/class/net/{}/address", name);
|
|
||||||
let file = File::open(&path)?;
|
|
||||||
file.take(len as u64).read_to_string(&mut mac)?;
|
|
||||||
|
|
||||||
Ok(mac)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl NetDevice {
|
impl NetDevice {
|
||||||
/// Attempts to open a network device in read-write mode
|
/// Attempts to open a network device in read-write mode
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<NetDevice> {
|
pub fn open(adapter: u32, device: u32) -> Result<NetDevice> {
|
||||||
|
let path = format!("/dev/dvb/adapter{}/net{}", adapter, device);
|
||||||
let file = OpenOptions::new()
|
let file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.custom_flags(::nix::libc::O_NONBLOCK)
|
.custom_flags(::nix::libc::O_NONBLOCK)
|
||||||
.open(path)
|
.open(&path)
|
||||||
.context("NET: open")?;
|
.context("NET: open")?;
|
||||||
|
|
||||||
let name = read_interface_name(&file).context("NET: read interface name")?;
|
|
||||||
let mac = read_mac_address(&name).unwrap_or_else(|_| EMPTY_MAC.to_owned());
|
|
||||||
|
|
||||||
let net = NetDevice {
|
let net = NetDevice {
|
||||||
|
adapter,
|
||||||
|
device,
|
||||||
file,
|
file,
|
||||||
name,
|
|
||||||
mac,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(net)
|
Ok(net)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns interface name in format `dvb{0}_{1}` where `{0}` is adapter number
|
/// Creates a new network interface and returns interface number
|
||||||
/// and `{1}` is a device number
|
pub fn add_if(&self, pid: u16, feedtype: u8) -> Result<NetInterface> {
|
||||||
pub fn get_name(&self) -> &str { self.name.as_str() }
|
let mut data = DvbNetIf {
|
||||||
|
pid,
|
||||||
|
if_num: 0,
|
||||||
|
feedtype,
|
||||||
|
};
|
||||||
|
|
||||||
/// Returns interface MAC address
|
|
||||||
pub fn get_mac(&self) -> &str { self.mac.as_str() }
|
|
||||||
|
|
||||||
/// Creates a new network interface
|
|
||||||
pub fn add_if(&self, data: &mut DvbNetIf) -> Result<()> {
|
|
||||||
// NET_ADD_IF
|
// NET_ADD_IF
|
||||||
ioctl_readwrite!(#[inline] ioctl_call, b'o', 52, DvbNetIf);
|
ioctl_readwrite!(#[inline] ioctl_call, b'o', 52, DvbNetIf);
|
||||||
unsafe {
|
unsafe {
|
||||||
ioctl_call(self.as_raw_fd(), data as *mut _)
|
ioctl_call(self.as_raw_fd(), &mut data as *mut _)
|
||||||
}.context("NET: add if")?;
|
}.context("NET: add if")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(NetInterface {
|
||||||
|
net: self,
|
||||||
|
if_num: data.if_num,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a network interface
|
/// Removes a network interface
|
||||||
pub fn remove_if(&self, data: &DvbNetIf) -> Result<()> {
|
pub fn remove_if(&self, interface: NetInterface) -> Result<()> {
|
||||||
// NET_REMOVE_IF
|
// NET_REMOVE_IF
|
||||||
ioctl_write_int_bad!(#[inline] ioctl_call, request_code_none!(b'o', 53));
|
ioctl_write_int_bad!(#[inline] ioctl_call, request_code_none!(b'o', 53));
|
||||||
unsafe {
|
unsafe {
|
||||||
ioctl_call(self.as_raw_fd(), data.if_num as _)
|
ioctl_call(self.as_raw_fd(), i32::from(interface.if_num))
|
||||||
}.context("NET: remove if")?;
|
}.context("NET: remove if")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct NetInterface<'a> {
|
||||||
|
net: &'a NetDevice,
|
||||||
|
if_num: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for NetInterface<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self.net.device == 0 {
|
||||||
|
write!(f, "dvb{}_{}", self.net.adapter, self.if_num)
|
||||||
|
} else {
|
||||||
|
write!(f, "dvb{}{}{}", self.net.adapter, self.net.device, self.if_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> NetInterface<'a> {
|
||||||
|
/// Returns interface mac address or empty mac on any error
|
||||||
|
pub fn get_mac(&self) -> String {
|
||||||
|
let path = format!("/sys/class/net/{}/address", self);
|
||||||
|
let file = match File::open(&path) {
|
||||||
|
Ok(v) => v,
|
||||||
|
_ => return EMPTY_MAC.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mac = String::with_capacity(MAC_SIZE);
|
||||||
|
let result = file
|
||||||
|
.take(MAC_SIZE as u64)
|
||||||
|
.read_to_string(&mut mac);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(MAC_SIZE) => mac,
|
||||||
|
_ => EMPTY_MAC.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user