libdvb_rs/net/
mod.rs

1pub mod sys;
2
3use {
4    anyhow::{Context, Result},
5    nix::{ioctl_readwrite, ioctl_write_int_bad, request_code_none},
6    std::{
7        fmt,
8        fs::{File, OpenOptions},
9        io::Read,
10        os::unix::{
11            fs::OpenOptionsExt,
12            io::{AsRawFd, RawFd},
13        },
14    },
15    sys::*,
16};
17
18pub const EMPTY_MAC: &str = "00:00:00:00:00:00";
19const MAC_SIZE: usize = EMPTY_MAC.len();
20
21/// A reference to the network device
22#[derive(Debug)]
23pub struct NetDevice {
24    adapter: u32,
25    device: u32,
26
27    file: File,
28}
29
30impl AsRawFd for NetDevice {
31    #[inline]
32    fn as_raw_fd(&self) -> RawFd {
33        self.file.as_raw_fd()
34    }
35}
36
37impl NetDevice {
38    /// Attempts to open a network device in read-write mode
39    pub fn open(adapter: u32, device: u32) -> Result<NetDevice> {
40        let path = format!("/dev/dvb/adapter{}/net{}", adapter, device);
41        let file = OpenOptions::new()
42            .read(true)
43            .write(true)
44            .custom_flags(::nix::libc::O_NONBLOCK)
45            .open(&path)
46            .with_context(|| format!("NET: failed to open device {}", &path))?;
47
48        let net = NetDevice {
49            adapter,
50            device,
51            file,
52        };
53
54        Ok(net)
55    }
56
57    /// Creates a new network interface and returns interface number
58    pub fn add_if(&self, pid: u16, feedtype: u8) -> Result<NetInterface> {
59        let mut data = DvbNetIf {
60            pid,
61            if_num: 0,
62            feedtype,
63        };
64
65        // NET_ADD_IF
66        ioctl_readwrite!(
67            #[inline]
68            ioctl_call,
69            b'o',
70            52,
71            DvbNetIf
72        );
73        unsafe { ioctl_call(self.as_raw_fd(), &mut data as *mut _) }.context("NET: add if")?;
74
75        Ok(NetInterface {
76            net: self,
77            if_num: data.if_num,
78        })
79    }
80
81    /// Removes a network interface
82    pub fn remove_if(&self, interface: NetInterface) -> Result<()> {
83        // NET_REMOVE_IF
84        ioctl_write_int_bad!(
85            #[inline]
86            ioctl_call,
87            request_code_none!(b'o', 53)
88        );
89        unsafe { ioctl_call(self.as_raw_fd(), i32::from(interface.if_num)) }
90            .context("NET: remove if")?;
91
92        Ok(())
93    }
94}
95
96pub struct NetInterface<'a> {
97    net: &'a NetDevice,
98    if_num: u16,
99}
100
101impl<'a> fmt::Display for NetInterface<'a> {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        if self.net.device == 0 {
104            write!(f, "dvb{}_{}", self.net.adapter, self.if_num)
105        } else {
106            write!(
107                f,
108                "dvb{}{}{}",
109                self.net.adapter, self.net.device, self.if_num
110            )
111        }
112    }
113}
114
115impl<'a> NetInterface<'a> {
116    /// Returns interface mac address or empty mac on any error
117    pub fn get_mac(&self) -> String {
118        let path = format!("/sys/class/net/{}/address", self);
119        let file = match File::open(&path) {
120            Ok(v) => v,
121            _ => return EMPTY_MAC.to_owned(),
122        };
123
124        let mut mac = String::with_capacity(MAC_SIZE);
125        let result = file.take(MAC_SIZE as u64).read_to_string(&mut mac);
126
127        match result {
128            Ok(MAC_SIZE) => mac,
129            _ => EMPTY_MAC.to_owned(),
130        }
131    }
132}