Skip to main content

systemconfiguration/
network_interface.rs

1use serde::Deserialize;
2
3use crate::{bridge, error::Result, ffi, PropertyList, SystemConfigurationError};
4
5#[derive(Clone, Debug)]
6pub struct NetworkInterface {
7    raw: bridge::OwnedHandle,
8}
9
10#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
11pub struct NetworkInterfaceMtuInfo {
12    pub current: i32,
13    pub minimum: i32,
14    pub maximum: i32,
15}
16
17#[derive(Clone, Debug)]
18pub struct NetworkInterfaceMediaOptions {
19    pub current: Option<PropertyList>,
20    pub active: Option<PropertyList>,
21    pub available: Option<PropertyList>,
22}
23
24impl NetworkInterface {
25    pub fn type_id() -> u64 {
26        unsafe { ffi::network_interface::sc_network_interface_get_type_id() }
27    }
28
29    pub fn copy_all() -> Result<Vec<Self>> {
30        let raw = unsafe { ffi::network_interface::sc_network_interface_copy_all() };
31        if raw.is_null() {
32            return Err(SystemConfigurationError::last(
33                "sc_network_interface_copy_all",
34            ));
35        }
36        Ok(bridge::take_handle_array(raw, Self::from_owned_handle))
37    }
38
39    pub fn ipv4() -> Result<Self> {
40        let raw = unsafe { ffi::network_interface::sc_network_interface_copy_ipv4() };
41        let raw = bridge::owned_handle_or_last("sc_network_interface_copy_ipv4", raw)?;
42        Ok(Self::from_owned_handle(raw))
43    }
44
45    pub fn supported_interface_types(&self) -> Vec<String> {
46        bridge::take_string_array(unsafe {
47            ffi::network_interface::sc_network_interface_copy_supported_interface_types(
48                self.raw.as_ptr(),
49            )
50        })
51    }
52
53    pub fn supported_protocol_types(&self) -> Vec<String> {
54        bridge::take_string_array(unsafe {
55            ffi::network_interface::sc_network_interface_copy_supported_protocol_types(
56                self.raw.as_ptr(),
57            )
58        })
59    }
60
61    pub fn create_layered_interface(&self, interface_type: &str) -> Result<Option<Self>> {
62        let interface_type =
63            bridge::cstring(interface_type, "sc_network_interface_create_with_interface")?;
64        let raw = unsafe {
65            ffi::network_interface::sc_network_interface_create_with_interface(
66                self.raw.as_ptr(),
67                interface_type.as_ptr(),
68            )
69        };
70        Ok(unsafe { bridge::OwnedHandle::from_raw(raw) }.map(Self::from_owned_handle))
71    }
72
73    pub fn bsd_name(&self) -> Result<Option<String>> {
74        Ok(bridge::take_optional_string(unsafe {
75            ffi::network_interface::sc_network_interface_copy_bsd_name(self.raw.as_ptr())
76        }))
77    }
78
79    pub fn configuration(&self) -> Option<PropertyList> {
80        unsafe {
81            bridge::OwnedHandle::from_raw(
82                ffi::network_interface::sc_network_interface_copy_configuration(self.raw.as_ptr()),
83            )
84        }
85        .map(PropertyList::from_owned_handle)
86    }
87
88    pub fn extended_configuration(&self, extended_type: &str) -> Result<Option<PropertyList>> {
89        let extended_type = bridge::cstring(
90            extended_type,
91            "sc_network_interface_copy_extended_configuration",
92        )?;
93        let raw = unsafe {
94            ffi::network_interface::sc_network_interface_copy_extended_configuration(
95                self.raw.as_ptr(),
96                extended_type.as_ptr(),
97            )
98        };
99        Ok(unsafe { bridge::OwnedHandle::from_raw(raw) }.map(PropertyList::from_owned_handle))
100    }
101
102    pub fn hardware_address_string(&self) -> Result<Option<String>> {
103        Ok(bridge::take_optional_string(unsafe {
104            ffi::network_interface::sc_network_interface_copy_hardware_address(self.raw.as_ptr())
105        }))
106    }
107
108    pub fn underlying_interface(&self) -> Option<Self> {
109        unsafe {
110            bridge::OwnedHandle::from_raw(
111                ffi::network_interface::sc_network_interface_copy_underlying_interface(
112                    self.raw.as_ptr(),
113                ),
114            )
115        }
116        .map(Self::from_owned_handle)
117    }
118
119    pub fn interface_type(&self) -> Result<Option<String>> {
120        Ok(bridge::take_optional_string(unsafe {
121            ffi::network_interface::sc_network_interface_copy_interface_type(self.raw.as_ptr())
122        }))
123    }
124
125    pub fn localized_display_name(&self) -> Result<Option<String>> {
126        Ok(bridge::take_optional_string(unsafe {
127            ffi::network_interface::sc_network_interface_copy_localized_display_name(
128                self.raw.as_ptr(),
129            )
130        }))
131    }
132
133    pub fn media_options(&self, filter: bool) -> NetworkInterfaceMediaOptions {
134        let current = unsafe {
135            bridge::OwnedHandle::from_raw(
136                ffi::network_interface::sc_network_interface_copy_media_options_current(
137                    self.raw.as_ptr(),
138                    u8::from(filter),
139                ),
140            )
141        }
142        .map(PropertyList::from_owned_handle);
143        let active = unsafe {
144            bridge::OwnedHandle::from_raw(
145                ffi::network_interface::sc_network_interface_copy_media_options_active(
146                    self.raw.as_ptr(),
147                    u8::from(filter),
148                ),
149            )
150        }
151        .map(PropertyList::from_owned_handle);
152        let available = unsafe {
153            bridge::OwnedHandle::from_raw(
154                ffi::network_interface::sc_network_interface_copy_media_options_available(
155                    self.raw.as_ptr(),
156                    u8::from(filter),
157                ),
158            )
159        }
160        .map(PropertyList::from_owned_handle);
161        NetworkInterfaceMediaOptions {
162            current,
163            active,
164            available,
165        }
166    }
167
168    pub fn media_subtypes(available: &PropertyList) -> Vec<String> {
169        bridge::take_string_array(unsafe {
170            ffi::network_interface::sc_network_interface_copy_media_subtypes(available.as_ptr())
171        })
172    }
173
174    pub fn media_subtype_options(
175        available: &PropertyList,
176        subtype: &str,
177    ) -> Result<Vec<Vec<String>>> {
178        let subtype = bridge::cstring(subtype, "sc_network_interface_copy_media_subtype_options")?;
179        bridge::parse_json("sc_network_interface_copy_media_subtype_options", unsafe {
180            ffi::network_interface::sc_network_interface_copy_media_subtype_options(
181                available.as_ptr(),
182                subtype.as_ptr(),
183            )
184        })
185    }
186
187    pub fn mtu_info(&self) -> Result<Option<NetworkInterfaceMtuInfo>> {
188        let raw = unsafe {
189            ffi::network_interface::sc_network_interface_copy_mtu_info(self.raw.as_ptr())
190        };
191        if raw.is_null() {
192            return Ok(None);
193        }
194        bridge::parse_json("sc_network_interface_copy_mtu_info", raw).map(Some)
195    }
196
197    pub fn set_configuration(&self, config: Option<&PropertyList>) -> Result<()> {
198        let ok = unsafe {
199            ffi::network_interface::sc_network_interface_set_configuration(
200                self.raw.as_ptr(),
201                config.map_or(std::ptr::null_mut(), PropertyList::as_ptr),
202            )
203        };
204        bridge::bool_result("sc_network_interface_set_configuration", ok)
205    }
206
207    pub fn set_extended_configuration(
208        &self,
209        extended_type: &str,
210        config: Option<&PropertyList>,
211    ) -> Result<()> {
212        let extended_type = bridge::cstring(
213            extended_type,
214            "sc_network_interface_set_extended_configuration",
215        )?;
216        let ok = unsafe {
217            ffi::network_interface::sc_network_interface_set_extended_configuration(
218                self.raw.as_ptr(),
219                extended_type.as_ptr(),
220                config.map_or(std::ptr::null_mut(), PropertyList::as_ptr),
221            )
222        };
223        bridge::bool_result("sc_network_interface_set_extended_configuration", ok)
224    }
225
226    pub fn set_media_options<S: AsRef<str>>(
227        &self,
228        subtype: Option<&str>,
229        options: &[S],
230    ) -> Result<()> {
231        let subtype = bridge::optional_cstring(subtype, "sc_network_interface_set_media_options")?;
232        let options = bridge::CStringArray::new(options, "sc_network_interface_set_media_options")?;
233        let ok = unsafe {
234            ffi::network_interface::sc_network_interface_set_media_options(
235                self.raw.as_ptr(),
236                subtype
237                    .as_ref()
238                    .map_or(std::ptr::null(), |value| value.as_ptr()),
239                options.as_ptr(),
240                options.count(),
241            )
242        };
243        bridge::bool_result("sc_network_interface_set_media_options", ok)
244    }
245
246    pub fn set_mtu(&self, mtu: i32) -> Result<()> {
247        let ok =
248            unsafe { ffi::network_interface::sc_network_interface_set_mtu(self.raw.as_ptr(), mtu) };
249        bridge::bool_result("sc_network_interface_set_mtu", ok)
250    }
251
252    pub fn force_configuration_refresh(&self) -> Result<()> {
253        let ok = unsafe {
254            ffi::network_interface::sc_network_interface_force_configuration_refresh(
255                self.raw.as_ptr(),
256            )
257        };
258        bridge::bool_result("sc_network_interface_force_configuration_refresh", ok)
259    }
260
261    pub(crate) fn from_owned_handle(raw: bridge::OwnedHandle) -> Self {
262        Self { raw }
263    }
264
265    pub(crate) fn as_ptr(&self) -> bridge::RawHandle {
266        self.raw.as_ptr()
267    }
268}