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