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}