1use core::num::NonZeroU32;
12use core::{ffi, fmt, ptr};
13
14use crate::ipv4;
15use crate::sys::*;
16
17use ::log::info;
18
19use crate::eventloop::{EspEventDeserializer, EspEventSource};
20use crate::handle::RawHandle;
21use crate::private::common::*;
22use crate::private::cstr::*;
23use crate::private::mutex;
24
25#[cfg(feature = "alloc")]
26pub use driver::*;
27#[cfg(esp_idf_lwip_ppp_support)]
28pub use ppp::*;
29
30#[derive(Copy, Clone, Debug, PartialEq, Eq)]
31#[cfg_attr(feature = "std", derive(Hash))]
32pub enum NetifStack {
33 Sta,
35 #[cfg(esp_idf_esp_wifi_softap_support)]
36 Ap,
38 Eth,
40 #[cfg(esp_idf_lwip_ppp_support)]
41 Ppp,
43 #[cfg(esp_idf_lwip_slip_support)]
44 Slip,
46 #[cfg(all(esp_idf_comp_openthread_enabled, esp_idf_openthread_enabled,))]
47 Thread,
48}
49
50impl NetifStack {
51 pub fn initialize() -> Result<(), EspError> {
62 initialize_netif_stack()
63 }
64
65 pub fn default_configuration(&self) -> NetifConfiguration {
66 match self {
67 Self::Sta => NetifConfiguration::wifi_default_client(),
68 #[cfg(esp_idf_esp_wifi_softap_support)]
69 Self::Ap => NetifConfiguration::wifi_default_router(),
70 Self::Eth => NetifConfiguration::eth_default_client(),
71 #[cfg(esp_idf_lwip_ppp_support)]
72 Self::Ppp => NetifConfiguration::ppp_default_client(),
73 #[cfg(esp_idf_lwip_slip_support)]
74 Self::Slip => NetifConfiguration::slip_default_client(),
75 #[cfg(all(esp_idf_comp_openthread_enabled, esp_idf_openthread_enabled,))]
76 Self::Thread => NetifConfiguration::thread_default(),
77 }
78 }
79
80 fn default_mac(&self) -> Result<Option<[u8; 6]>, EspError> {
81 if let Some(mac_type) = self.default_mac_raw_type() {
82 let mut mac = [0; 6];
83
84 let result = esp!(unsafe { esp_read_mac(mac.as_mut_ptr() as *mut _, mac_type) });
85
86 #[cfg(not(esp_idf_soc_wifi_supported))]
91 {
92 if result.is_ok() {
93 Ok(Some(mac))
94 } else {
95 Ok(None)
96 }
97 }
98
99 #[cfg(esp_idf_soc_wifi_supported)]
100 {
101 result?;
102
103 Ok(Some(mac))
104 }
105 } else {
106 Ok(None)
107 }
108 }
109
110 fn default_mac_raw_type(&self) -> Option<esp_mac_type_t> {
111 match self {
112 Self::Sta => Some(esp_mac_type_t_ESP_MAC_WIFI_STA),
113 #[cfg(esp_idf_esp_wifi_softap_support)]
114 Self::Ap => Some(esp_mac_type_t_ESP_MAC_WIFI_SOFTAP),
115 Self::Eth => Some(esp_mac_type_t_ESP_MAC_ETH),
116 #[cfg(all(esp_idf_comp_openthread_enabled, esp_idf_openthread_enabled,))]
117 Self::Thread => {
118 #[cfg(esp_idf_soc_ieee802154_supported)]
119 let mac_type = Some(esp_mac_type_t_ESP_MAC_IEEE802154);
120
121 #[cfg(not(esp_idf_soc_ieee802154_supported))]
122 let mac_type = None;
123
124 mac_type
125 }
126 #[cfg(any(esp_idf_lwip_slip_support, esp_idf_lwip_ppp_support))]
127 _ => None,
128 }
129 }
130
131 fn default_raw_stack(&self) -> *const esp_netif_netstack_config_t {
132 unsafe {
133 match self {
134 Self::Sta => _g_esp_netif_netstack_default_wifi_sta,
135 #[cfg(esp_idf_esp_wifi_softap_support)]
136 Self::Ap => _g_esp_netif_netstack_default_wifi_ap,
137 Self::Eth => _g_esp_netif_netstack_default_eth,
138 #[cfg(esp_idf_lwip_ppp_support)]
139 Self::Ppp => _g_esp_netif_netstack_default_ppp,
140 #[cfg(esp_idf_lwip_slip_support)]
141 Self::Slip => _g_esp_netif_netstack_default_slip,
142 #[cfg(all(
143 esp_idf_comp_openthread_enabled,
144 esp_idf_openthread_enabled,
145 esp_idf_version_major = "4"
146 ))]
147 Self::Thread => _g_esp_netif_netstack_default_openthread,
148 #[cfg(all(
149 esp_idf_comp_openthread_enabled,
150 esp_idf_openthread_enabled,
151 not(esp_idf_version_major = "4")
152 ))]
153 Self::Thread => &g_esp_netif_netstack_default_openthread,
154 }
155 }
156 }
157}
158
159#[derive(Clone, Debug, PartialEq, Eq)]
160pub struct NetifConfiguration {
161 pub flags: u32,
162 pub got_ip_event_id: Option<NonZeroU32>,
163 pub lost_ip_event_id: Option<NonZeroU32>,
164 pub key: heapless::String<32>,
165 pub description: heapless::String<8>,
166 pub route_priority: u32,
167 pub ip_configuration: Option<ipv4::Configuration>,
168 pub stack: NetifStack,
169 pub custom_mac: Option<[u8; 6]>,
170}
171
172impl NetifConfiguration {
173 pub fn eth_default_client() -> Self {
174 Self {
175 flags: esp_netif_flags_ESP_NETIF_FLAG_GARP
176 | esp_netif_flags_ESP_NETIF_FLAG_EVENT_IP_MODIFIED,
177 got_ip_event_id: NonZeroU32::new(ip_event_t_IP_EVENT_ETH_GOT_IP as _),
178 lost_ip_event_id: NonZeroU32::new(ip_event_t_IP_EVENT_ETH_LOST_IP as _),
179 key: "ETH_DEF".try_into().unwrap(),
180 description: "eth".try_into().unwrap(),
181 route_priority: 60,
182 ip_configuration: Some(ipv4::Configuration::Client(Default::default())),
183 stack: NetifStack::Eth,
184 custom_mac: None,
185 }
186 }
187
188 pub fn eth_default_router() -> Self {
189 Self {
190 flags: 0,
191 got_ip_event_id: None,
192 lost_ip_event_id: None,
193 key: "ETH_RT_DEF".try_into().unwrap(),
194 description: "ethrt".try_into().unwrap(),
195 route_priority: 50,
196 ip_configuration: Some(ipv4::Configuration::Router(Default::default())),
197 stack: NetifStack::Eth,
198 custom_mac: None,
199 }
200 }
201
202 pub fn wifi_default_client() -> Self {
203 Self {
204 flags: esp_netif_flags_ESP_NETIF_FLAG_GARP
205 | esp_netif_flags_ESP_NETIF_FLAG_EVENT_IP_MODIFIED,
206 got_ip_event_id: NonZeroU32::new(ip_event_t_IP_EVENT_STA_GOT_IP as _),
207 lost_ip_event_id: NonZeroU32::new(ip_event_t_IP_EVENT_STA_LOST_IP as _),
208 key: "WIFI_STA_DEF".try_into().unwrap(),
209 description: "sta".try_into().unwrap(),
210 route_priority: 100,
211 ip_configuration: Some(ipv4::Configuration::Client(Default::default())),
212 stack: NetifStack::Sta,
213 custom_mac: None,
214 }
215 }
216
217 #[cfg(esp_idf_esp_wifi_softap_support)]
218 pub fn wifi_default_router() -> Self {
219 Self {
220 flags: 0,
221 got_ip_event_id: None,
222 lost_ip_event_id: None,
223 key: "WIFI_AP_DEF".try_into().unwrap(),
224 description: "ap".try_into().unwrap(),
225 route_priority: 10,
226 ip_configuration: Some(ipv4::Configuration::Router(Default::default())),
227 stack: NetifStack::Ap,
228 custom_mac: None,
229 }
230 }
231
232 #[cfg(esp_idf_lwip_ppp_support)]
233 pub fn ppp_default_client() -> Self {
234 Self {
235 flags: esp_netif_flags_ESP_NETIF_FLAG_IS_PPP,
236 got_ip_event_id: NonZeroU32::new(ip_event_t_IP_EVENT_PPP_GOT_IP as _),
237 lost_ip_event_id: NonZeroU32::new(ip_event_t_IP_EVENT_PPP_LOST_IP as _),
238 key: "PPP_CL_DEF".try_into().unwrap(),
239 description: "ppp".try_into().unwrap(),
240 route_priority: 30,
241 ip_configuration: Some(ipv4::Configuration::Client(Default::default())),
242 stack: NetifStack::Ppp,
243 custom_mac: None,
244 }
245 }
246
247 #[cfg(esp_idf_lwip_ppp_support)]
248 pub fn ppp_default_router() -> Self {
249 Self {
250 flags: esp_netif_flags_ESP_NETIF_FLAG_IS_PPP,
251 got_ip_event_id: None,
252 lost_ip_event_id: None,
253 key: "PPP_RT_DEF".try_into().unwrap(),
254 description: "ppprt".try_into().unwrap(),
255 route_priority: 20,
256 ip_configuration: Some(ipv4::Configuration::Router(Default::default())),
257 stack: NetifStack::Ppp,
258 custom_mac: None,
259 }
260 }
261
262 #[cfg(esp_idf_lwip_slip_support)]
263 pub fn slip_default_client() -> Self {
264 Self {
265 flags: 0,
266 get_ip_event: None,
267 lost_ip_event: None,
268 key: "SLIP_CL_DEF".try_into().unwrap(),
269 description: "slip".try_into().unwrap(),
270 route_priority: 35,
271 ip_configuration: Some(ipv4::Configuration::Client(Default::default())),
272 stack: NetifStack::Slip,
273 custom_mac: None,
274 }
275 }
276
277 #[cfg(esp_idf_lwip_slip_support)]
278 pub fn slip_default_router() -> Self {
279 Self {
280 flags: 0,
281 get_ip_event: None,
282 lost_ip_event: None,
283 key: "SLIP_RT_DEF".try_into().unwrap(),
284 description: "sliprt".try_into().unwrap(),
285 route_priority: 25,
286 ip_configuration: Some(ipv4::Configuration::Router(Default::default())),
287 stack: NetifStack::Slip,
288 custom_mac: None,
289 }
290 }
291
292 #[cfg(all(esp_idf_comp_openthread_enabled, esp_idf_openthread_enabled,))]
293 pub fn thread_default() -> Self {
294 Self {
295 flags: 0,
296 got_ip_event_id: None,
297 lost_ip_event_id: None,
298 key: "OT_DEF".try_into().unwrap(),
299 description: "thread".try_into().unwrap(),
300 route_priority: 15,
301 ip_configuration: None,
302 stack: NetifStack::Thread,
303 custom_mac: None,
304 }
305 }
306}
307
308static INITALIZED: mutex::Mutex<bool> = mutex::Mutex::new(false);
309
310fn initialize_netif_stack() -> Result<(), EspError> {
311 let mut guard = INITALIZED.lock();
312
313 if !*guard {
314 esp!(unsafe { esp_netif_init() })?;
315
316 *guard = true;
317 }
318
319 Ok(())
320}
321
322#[derive(Debug)]
323pub struct EspNetif {
324 handle: *mut esp_netif_t,
325 _got_ip_event_id: Option<NonZeroU32>,
326 _lost_ip_event_id: Option<NonZeroU32>,
327}
328
329impl EspNetif {
330 pub fn new(stack: NetifStack) -> Result<Self, EspError> {
331 Self::new_with_conf(&stack.default_configuration())
332 }
333
334 pub fn new_with_conf(conf: &NetifConfiguration) -> Result<Self, EspError> {
335 initialize_netif_stack()?;
336
337 let c_if_key = to_cstring_arg(conf.key.as_str())?;
338 let c_if_description = to_cstring_arg(conf.description.as_str())?;
339
340 let initial_mac = if let Some(custom_mac) = conf.custom_mac {
341 custom_mac
342 } else {
343 conf.stack.default_mac()?.unwrap_or([0; 6])
344 };
345
346 let (mut esp_inherent_config, ip_info, dhcps, dns, secondary_dns, hostname) = match conf
347 .ip_configuration
348 {
349 Some(ipv4::Configuration::Client(ref ip_conf)) => (
350 esp_netif_inherent_config_t {
351 flags: conf.flags
352 | (if matches!(ip_conf, ipv4::ClientConfiguration::DHCP(_)) {
353 esp_netif_flags_ESP_NETIF_DHCP_CLIENT
354 } else {
355 0
356 }),
357 mac: initial_mac,
358 ip_info: ptr::null(),
359 get_ip_event: conf.got_ip_event_id.map(NonZeroU32::get).unwrap_or(0),
360 lost_ip_event: conf.lost_ip_event_id.map(NonZeroU32::get).unwrap_or(0),
361 if_key: c_if_key.as_c_str().as_ptr() as _,
362 if_desc: c_if_description.as_c_str().as_ptr() as _,
363 route_prio: conf.route_priority as _,
364 #[cfg(not(esp_idf_version_major = "4"))]
365 bridge_info: ptr::null_mut(),
366 #[cfg(esp_idf_version_at_least_6_0_0)]
367 mtu: 0,
368 },
369 match ip_conf {
370 ipv4::ClientConfiguration::DHCP(_) => None,
371 ipv4::ClientConfiguration::Fixed(ref fixed_conf) => Some(esp_netif_ip_info_t {
372 ip: Newtype::<esp_ip4_addr_t>::from(fixed_conf.ip).0,
373 netmask: Newtype::<esp_ip4_addr_t>::from(fixed_conf.subnet.mask).0,
374 gw: Newtype::<esp_ip4_addr_t>::from(fixed_conf.subnet.gateway).0,
375 }),
376 },
377 false,
378 match ip_conf {
379 ipv4::ClientConfiguration::DHCP(_) => None,
380 ipv4::ClientConfiguration::Fixed(ref fixed_conf) => fixed_conf.dns,
381 },
382 match ip_conf {
383 ipv4::ClientConfiguration::DHCP(_) => None,
384 ipv4::ClientConfiguration::Fixed(ref fixed_conf) => fixed_conf.secondary_dns,
385 },
386 match ip_conf {
387 ipv4::ClientConfiguration::DHCP(ref dhcp_conf) => dhcp_conf.hostname.as_ref(),
388 ipv4::ClientConfiguration::Fixed(_) => None,
389 },
390 ),
391 Some(ipv4::Configuration::Router(ref ip_conf)) => (
392 esp_netif_inherent_config_t {
393 flags: conf.flags
394 | (if ip_conf.dhcp_enabled {
395 esp_netif_flags_ESP_NETIF_DHCP_SERVER
396 } else {
397 0
398 })
399 | esp_netif_flags_ESP_NETIF_FLAG_AUTOUP,
400 mac: initial_mac,
401 ip_info: ptr::null(),
402 get_ip_event: conf.got_ip_event_id.map(NonZeroU32::get).unwrap_or(0),
403 lost_ip_event: conf.lost_ip_event_id.map(NonZeroU32::get).unwrap_or(0),
404 if_key: c_if_key.as_c_str().as_ptr() as _,
405 if_desc: c_if_description.as_c_str().as_ptr() as _,
406 route_prio: conf.route_priority as _,
407 #[cfg(not(esp_idf_version_major = "4"))]
408 bridge_info: ptr::null_mut(),
409 #[cfg(esp_idf_version_at_least_6_0_0)]
410 mtu: 0,
411 },
412 Some(esp_netif_ip_info_t {
413 ip: Newtype::<esp_ip4_addr_t>::from(ip_conf.subnet.gateway).0,
414 netmask: Newtype::<esp_ip4_addr_t>::from(ip_conf.subnet.mask).0,
415 gw: Newtype::<esp_ip4_addr_t>::from(ip_conf.subnet.gateway).0,
416 }),
417 ip_conf.dhcp_enabled,
418 ip_conf.dns,
419 None, None,
421 ),
422 None => (
423 esp_netif_inherent_config_t {
424 flags: conf.flags | esp_netif_flags_ESP_NETIF_FLAG_AUTOUP,
425 mac: initial_mac,
426 ip_info: ptr::null(),
427 get_ip_event: conf.got_ip_event_id.map(NonZeroU32::get).unwrap_or(0),
428 lost_ip_event: conf.lost_ip_event_id.map(NonZeroU32::get).unwrap_or(0),
429 if_key: c_if_key.as_c_str().as_ptr() as _,
430 if_desc: c_if_description.as_c_str().as_ptr() as _,
431 route_prio: conf.route_priority as _,
432 #[cfg(not(esp_idf_version_major = "4"))]
433 bridge_info: ptr::null_mut(),
434 #[cfg(esp_idf_version_at_least_6_0_0)]
435 mtu: 0,
436 },
437 None,
438 false,
439 None,
440 None,
441 None,
442 ),
443 };
444
445 if let Some(ip_info) = ip_info.as_ref() {
446 esp_inherent_config.ip_info = ip_info;
447 }
448
449 let cfg = esp_netif_config_t {
450 base: &esp_inherent_config,
451 driver: ptr::null(),
452 stack: conf.stack.default_raw_stack(),
453 };
454
455 let mut netif = Self {
456 handle: unsafe { esp_netif_new(&cfg).as_mut() }
457 .ok_or(EspError::from_infallible::<ESP_ERR_INVALID_ARG>())?,
458 _got_ip_event_id: conf.got_ip_event_id,
459 _lost_ip_event_id: conf.lost_ip_event_id,
460 };
461
462 if let Some(dns) = dns {
463 netif.set_dns(dns);
464
465 if dhcps {
466 #[cfg(esp_idf_version_major = "4")]
467 let mut dhcps_dns_value: dhcps_offer_t = dhcps_offer_option_OFFER_DNS as _;
468
469 #[cfg(not(esp_idf_version_major = "4"))]
471 let mut dhcps_dns_value: u8 = 2_u8;
472
473 esp!(unsafe {
474 esp_netif_dhcps_option(
475 netif.handle,
476 esp_netif_dhcp_option_mode_t_ESP_NETIF_OP_SET,
477 esp_netif_dhcp_option_id_t_ESP_NETIF_DOMAIN_NAME_SERVER,
478 &mut dhcps_dns_value as *mut _ as *mut _,
479 core::mem::size_of_val(&dhcps_dns_value) as u32,
480 )
481 })?;
482 }
483 }
484
485 if let Some(secondary_dns) = secondary_dns {
486 netif.set_secondary_dns(secondary_dns);
487 }
488
489 if let Some(hostname) = hostname {
490 netif.set_hostname(hostname)?;
491 }
492
493 Ok(netif)
494 }
495
496 pub fn is_netif_up(&self) -> Result<bool, EspError> {
497 Ok(unsafe { esp_netif_is_netif_up(self.handle) })
498 }
499
500 pub fn is_up(&self) -> Result<bool, EspError> {
502 if !self.is_netif_up()? {
503 Ok(false)
504 } else {
505 let mut ip_info = Default::default();
506 unsafe { esp!(esp_netif_get_ip_info(self.handle, &mut ip_info)) }?;
507
508 Ok(ipv4::IpInfo::from(Newtype(ip_info)).ip != ipv4::Ipv4Addr::new(0, 0, 0, 0))
509 }
510 }
511
512 pub fn get_ip_info(&self) -> Result<ipv4::IpInfo, EspError> {
513 let mut ip_info = Default::default();
514 unsafe { esp!(esp_netif_get_ip_info(self.handle, &mut ip_info)) }?;
515
516 Ok(ipv4::IpInfo {
517 dns: Some(self.get_dns()),
519 secondary_dns: Some(self.get_secondary_dns()),
520 ..Newtype(ip_info).into()
521 })
522 }
523
524 pub fn get_key(&self) -> heapless::String<32> {
525 unsafe { from_cstr_ptr(esp_netif_get_ifkey(self.handle)) }
526 .try_into()
527 .unwrap()
528 }
529
530 pub fn get_index(&self) -> u32 {
531 unsafe { esp_netif_get_netif_impl_index(self.handle) as _ }
532 }
533
534 pub fn get_name(&self) -> heapless::String<6> {
535 let mut netif_name = [0u8; 7];
536
537 esp!(unsafe {
538 esp_netif_get_netif_impl_name(self.handle, netif_name.as_mut_ptr() as *mut _)
539 })
540 .unwrap();
541
542 from_cstr(&netif_name).try_into().unwrap()
543 }
544
545 pub fn get_mac(&self) -> Result<[u8; 6], EspError> {
546 let mut mac = [0u8; 6];
547
548 esp!(unsafe { esp_netif_get_mac(self.handle, mac.as_mut_ptr() as *mut _) })?;
549 Ok(mac)
550 }
551
552 pub fn set_mac(&mut self, mac: &[u8; 6]) -> Result<(), EspError> {
553 esp!(unsafe { esp_netif_set_mac(self.handle, mac.as_ptr() as *mut _) })?;
554 Ok(())
555 }
556
557 pub fn get_dns(&self) -> ipv4::Ipv4Addr {
558 let mut dns_info = Default::default();
559
560 unsafe {
561 esp!(esp_netif_get_dns_info(
562 self.handle,
563 esp_netif_dns_type_t_ESP_NETIF_DNS_MAIN,
564 &mut dns_info
565 ))
566 .unwrap();
567
568 Newtype(dns_info.ip.u_addr.ip4).into()
569 }
570 }
571
572 fn set_dns(&mut self, dns: ipv4::Ipv4Addr) {
573 let mut dns_info: esp_netif_dns_info_t = Default::default();
574
575 unsafe {
576 dns_info.ip.u_addr.ip4 = Newtype::<esp_ip4_addr_t>::from(dns).0;
577
578 esp!(esp_netif_set_dns_info(
579 self.handle,
580 esp_netif_dns_type_t_ESP_NETIF_DNS_MAIN,
581 &mut dns_info
582 ))
583 .unwrap();
584 }
585 }
586
587 pub fn get_secondary_dns(&self) -> ipv4::Ipv4Addr {
588 let mut dns_info = Default::default();
589
590 unsafe {
591 esp!(esp_netif_get_dns_info(
592 self.handle,
593 esp_netif_dns_type_t_ESP_NETIF_DNS_BACKUP,
594 &mut dns_info
595 ))
596 .unwrap();
597
598 Newtype(dns_info.ip.u_addr.ip4).into()
599 }
600 }
601
602 fn set_secondary_dns(&mut self, secondary_dns: ipv4::Ipv4Addr) {
603 let mut dns_info: esp_netif_dns_info_t = Default::default();
604
605 unsafe {
606 dns_info.ip.u_addr.ip4 = Newtype::<esp_ip4_addr_t>::from(secondary_dns).0;
607
608 esp!(esp_netif_set_dns_info(
609 self.handle,
610 esp_netif_dns_type_t_ESP_NETIF_DNS_BACKUP,
611 &mut dns_info
612 ))
613 .unwrap();
614 }
615 }
616
617 pub fn get_hostname(&self) -> Result<heapless::String<30>, EspError> {
618 let mut ptr: *const ffi::c_char = ptr::null();
619 esp!(unsafe { esp_netif_get_hostname(self.handle, &mut ptr) })?;
620
621 Ok(unsafe { from_cstr_ptr(ptr) }.try_into().unwrap())
622 }
623
624 fn set_hostname(&mut self, hostname: &str) -> Result<(), EspError> {
625 let hostname = to_cstring_arg(hostname)?;
626
627 esp!(unsafe { esp_netif_set_hostname(self.handle, hostname.as_ptr() as *const _) })?;
628
629 Ok(())
630 }
631
632 #[cfg(esp_idf_lwip_ipv4_napt)]
633 pub fn enable_napt(&mut self, enable: bool) {
634 unsafe {
635 crate::sys::ip_napt_enable_no(
636 (esp_netif_get_netif_impl_index(self.handle) - 1) as u8,
637 if enable { 1 } else { 0 },
638 )
639 };
640 }
641}
642
643impl Drop for EspNetif {
644 fn drop(&mut self) {
645 unsafe { esp_netif_destroy(self.handle) };
646
647 info!("Dropped");
648 }
649}
650
651unsafe impl Send for EspNetif {}
652
653impl RawHandle for EspNetif {
654 type Handle = *mut esp_netif_t;
655
656 fn handle(&self) -> Self::Handle {
657 self.handle
658 }
659}
660
661#[derive(Copy, Clone)]
662pub struct ApStaIpAssignment<'a>(&'a ip_event_ap_staipassigned_t);
663
664impl ApStaIpAssignment<'_> {
665 #[cfg(not(esp_idf_version_major = "4"))]
666 pub fn netif_handle(&self) -> *mut esp_netif_t {
667 self.0.esp_netif
668 }
669
670 pub fn ip(&self) -> ipv4::Ipv4Addr {
671 ipv4::Ipv4Addr::from(Newtype(self.0.ip))
672 }
673
674 #[cfg(not(esp_idf_version_major = "4"))]
675 pub fn mac(&self) -> [u8; 6] {
676 self.0.mac
677 }
678}
679
680impl fmt::Debug for ApStaIpAssignment<'_> {
681 #[cfg(esp_idf_version_major = "4")]
682 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683 f.debug_struct("ApStaIpAssignment")
684 .field("ip", &self.ip())
685 .finish()
686 }
687
688 #[cfg(not(esp_idf_version_major = "4"))]
689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 f.debug_struct("ApStaIpAssignment")
691 .field("ip", &self.ip())
692 .field("mac", &self.mac())
693 .finish()
694 }
695}
696
697#[derive(Copy, Clone)]
698pub struct DhcpIpAssignment<'a>(&'a ip_event_got_ip_t);
699
700impl DhcpIpAssignment<'_> {
701 pub fn netif_handle(&self) -> *mut esp_netif_t {
702 self.0.esp_netif
703 }
704
705 pub fn ip(&self) -> ipv4::Ipv4Addr {
706 ipv4::Ipv4Addr::from(Newtype(self.0.ip_info.ip))
707 }
708
709 pub fn gateway(&self) -> ipv4::Ipv4Addr {
710 ipv4::Ipv4Addr::from(Newtype(self.0.ip_info.gw))
711 }
712
713 pub fn mask(&self) -> ipv4::Mask {
714 Newtype(self.0.ip_info.netmask).try_into().unwrap()
715 }
716
717 pub fn ip_info(&self) -> ipv4::IpInfo {
718 ipv4::IpInfo {
719 ip: self.ip(),
720 subnet: ipv4::Subnet {
721 gateway: self.gateway(),
722 mask: self.mask(),
723 },
724 dns: None, secondary_dns: None, }
727 }
728
729 pub fn is_ip_changed(&self) -> bool {
730 self.0.ip_changed
731 }
732}
733
734impl fmt::Debug for DhcpIpAssignment<'_> {
735 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
736 f.debug_struct("DhcpIpAssignment")
737 .field("netif_handle", &self.netif_handle())
738 .field("ip", &self.ip())
739 .field("gateway", &self.gateway())
740 .field("mask", &self.mask())
741 .field("is_ip_changed", &self.is_ip_changed())
742 .finish()
743 }
744}
745
746#[derive(Copy, Clone)]
747pub struct DhcpIp6Assignment<'a>(&'a ip_event_got_ip6_t);
748
749impl DhcpIp6Assignment<'_> {
750 pub fn netif_handle(&self) -> *mut esp_netif_t {
751 self.0.esp_netif
752 }
753
754 pub fn addr(&self) -> core::net::Ipv6Addr {
755 Newtype(self.0.ip6_info.ip).into()
756 }
757
758 pub fn ip(&self) -> [u32; 4] {
759 self.0.ip6_info.ip.addr
760 }
761
762 pub fn ip_zone(&self) -> u8 {
763 self.0.ip6_info.ip.zone
764 }
765
766 pub fn ip_index(&self) -> u32 {
767 self.0.ip_index as _
768 }
769}
770
771impl fmt::Debug for DhcpIp6Assignment<'_> {
772 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
773 f.debug_struct("DhcpIp6Assignment")
774 .field("netif_handle", &self.netif_handle())
775 .field("addr", &self.addr())
776 .field("ip_zone", &self.ip_zone())
777 .field("ip_index", &self.ip_index())
778 .finish()
779 }
780}
781
782#[derive(Copy, Clone, Debug)]
783pub enum IpEvent<'a> {
784 ApStaIpAssigned(ApStaIpAssignment<'a>),
785 DhcpIpAssigned(DhcpIpAssignment<'a>),
786 DhcpIp6Assigned(DhcpIp6Assignment<'a>),
787 DhcpIpDeassigned(*mut esp_netif_t),
788
789 Other(i32),
795}
796
797unsafe impl Send for IpEvent<'_> {}
798
799impl IpEvent<'_> {
800 pub fn is_for(&self, raw_handle: &impl RawHandle<Handle = *mut esp_netif_t>) -> bool {
801 self.is_for_handle(raw_handle.handle())
802 }
803
804 pub fn is_for_handle(&self, handle: *mut esp_netif_t) -> bool {
805 self.handle()
806 .map(|event_handle| core::ptr::eq(event_handle, handle))
807 .unwrap_or(false)
808 }
809
810 pub fn handle(&self) -> Option<*mut esp_netif_t> {
811 match self {
812 #[cfg(not(esp_idf_version_major = "4"))]
813 Self::ApStaIpAssigned(assignment) => Some(assignment.netif_handle()),
814 #[cfg(esp_idf_version_major = "4")]
815 Self::ApStaIpAssigned(_) => None,
816 Self::DhcpIpAssigned(assignment) => Some(assignment.netif_handle()),
817 Self::DhcpIp6Assigned(assignment) => Some(assignment.netif_handle()),
818 Self::DhcpIpDeassigned(handle) => Some(*handle),
819 Self::Other(_) => None,
820 }
821 }
822}
823
824unsafe impl EspEventSource for IpEvent<'_> {
825 fn source() -> Option<&'static ffi::CStr> {
826 Some(unsafe { CStr::from_ptr(IP_EVENT) })
827 }
828}
829
830impl EspEventDeserializer for IpEvent<'_> {
831 type Data<'d> = IpEvent<'d>;
832
833 #[allow(non_upper_case_globals, non_snake_case)]
834 fn deserialize<'d>(data: &crate::eventloop::EspEvent<'d>) -> IpEvent<'d> {
835 let event_id = data.event_id as u32;
836
837 if event_id == ip_event_t_IP_EVENT_AP_STAIPASSIGNED {
838 let event = unsafe {
839 (data.payload.unwrap() as *const _ as *const ip_event_ap_staipassigned_t)
840 .as_ref()
841 .unwrap()
842 };
843
844 IpEvent::ApStaIpAssigned(ApStaIpAssignment(event))
845 } else if event_id == ip_event_t_IP_EVENT_STA_GOT_IP
846 || event_id == ip_event_t_IP_EVENT_ETH_GOT_IP
847 || event_id == ip_event_t_IP_EVENT_PPP_GOT_IP
848 {
849 let event = unsafe {
850 (data.payload.unwrap() as *const _ as *const ip_event_got_ip_t)
851 .as_ref()
852 .unwrap()
853 };
854
855 IpEvent::DhcpIpAssigned(DhcpIpAssignment(event))
856 } else if event_id == ip_event_t_IP_EVENT_GOT_IP6 {
857 let event = unsafe {
858 (data.payload.unwrap() as *const _ as *const ip_event_got_ip6_t)
859 .as_ref()
860 .unwrap()
861 };
862
863 IpEvent::DhcpIp6Assigned(DhcpIp6Assignment(event))
864 } else if event_id == ip_event_t_IP_EVENT_STA_LOST_IP
865 || event_id == ip_event_t_IP_EVENT_PPP_LOST_IP
866 || event_id == ip_event_t_IP_EVENT_ETH_LOST_IP
867 {
868 let netif_handle_mut = unsafe {
869 (data.payload.unwrap() as *const _ as *mut esp_netif_t)
870 .as_mut()
871 .unwrap()
872 };
873
874 IpEvent::DhcpIpDeassigned(netif_handle_mut as *mut _)
875 } else {
876 ::log::warn!("IpEvent: unknown event ID {event_id}, ignoring");
877 IpEvent::Other(event_id as i32)
878 }
879 }
880}
881
882pub trait NetifStatus {
883 fn is_up(&self) -> Result<bool, EspError>;
884}
885
886impl<T> NetifStatus for &T
887where
888 T: NetifStatus,
889{
890 fn is_up(&self) -> Result<bool, EspError> {
891 (**self).is_up()
892 }
893}
894
895impl<T> NetifStatus for &mut T
896where
897 T: NetifStatus,
898{
899 fn is_up(&self) -> Result<bool, EspError> {
900 (**self).is_up()
901 }
902}
903
904impl NetifStatus for EspNetif {
905 fn is_up(&self) -> Result<bool, EspError> {
906 EspNetif::is_up(self)
907 }
908}
909
910const UP_TIMEOUT: core::time::Duration = core::time::Duration::from_secs(15);
911
912pub struct BlockingNetif<T> {
913 netif: T,
914 event_loop: crate::eventloop::EspSystemEventLoop,
915}
916
917impl<T> BlockingNetif<T>
918where
919 T: NetifStatus,
920{
921 pub fn wrap(netif: T, event_loop: crate::eventloop::EspSystemEventLoop) -> Self {
922 Self { netif, event_loop }
923 }
924
925 pub fn is_up(&self) -> Result<bool, EspError> {
926 self.netif.is_up()
927 }
928
929 pub fn wait_netif_up(&self) -> Result<(), EspError> {
930 self.ip_wait_while(|| self.netif.is_up().map(|s| !s), Some(UP_TIMEOUT))
931 }
932
933 pub fn ip_wait_while<F: Fn() -> Result<bool, EspError>>(
934 &self,
935 matcher: F,
936 timeout: Option<core::time::Duration>,
937 ) -> Result<(), EspError> {
938 let wait = crate::eventloop::Wait::new::<IpEvent>(&self.event_loop)?;
939
940 wait.wait_while(matcher, timeout)
941 }
942}
943
944impl<T> NetifStatus for BlockingNetif<T>
945where
946 T: NetifStatus,
947{
948 fn is_up(&self) -> Result<bool, EspError> {
949 BlockingNetif::is_up(self)
950 }
951}
952
953#[cfg(all(feature = "alloc", esp_idf_comp_esp_timer_enabled))]
954pub struct AsyncNetif<T> {
955 netif: T,
956 event_loop: crate::eventloop::EspSystemEventLoop,
957 timer_service: crate::timer::EspTaskTimerService,
958}
959
960#[cfg(all(feature = "alloc", esp_idf_comp_esp_timer_enabled))]
961impl<T> AsyncNetif<T>
962where
963 T: NetifStatus,
964{
965 pub fn wrap(
966 netif: T,
967 event_loop: crate::eventloop::EspSystemEventLoop,
968 timer_service: crate::timer::EspTaskTimerService,
969 ) -> Self {
970 Self {
971 netif,
972 event_loop,
973 timer_service,
974 }
975 }
976
977 pub fn is_up(&self) -> Result<bool, EspError> {
978 self.netif.is_up()
979 }
980
981 pub async fn wait_netif_up(&mut self) -> Result<(), EspError> {
982 self.ip_wait_while(|this| this.netif.is_up().map(|s| !s), Some(UP_TIMEOUT))
983 .await
984 }
985
986 pub async fn ip_wait_while<F: FnMut(&mut Self) -> Result<bool, EspError>>(
987 &mut self,
988 mut matcher: F,
989 timeout: Option<core::time::Duration>,
990 ) -> Result<(), EspError> {
991 let mut wait =
992 crate::eventloop::AsyncWait::<IpEvent, _>::new(&self.event_loop, &self.timer_service)?;
993
994 wait.wait_while(|| matcher(self), timeout).await
995 }
996}
997
998#[cfg(feature = "alloc")]
999mod driver {
1000 use core::borrow::BorrowMut;
1001
1002 use ::log::debug;
1003
1004 use crate::handle::RawHandle;
1005 use crate::sys::*;
1006
1007 use super::EspNetif;
1008
1009 pub struct EspNetifDriver<'d, T>
1010 where
1011 T: BorrowMut<EspNetif>,
1012 {
1013 inner: alloc::boxed::Box<EspNetifDriverInner<'d, T>>,
1014 started: bool,
1015 }
1016
1017 impl<T> EspNetifDriver<'static, T>
1018 where
1019 T: BorrowMut<EspNetif>,
1020 {
1021 pub fn new<P, F>(netif: T, post_attach_cfg: P, tx: F) -> Result<Self, EspError>
1064 where
1065 P: FnMut(&mut EspNetif) -> Result<(), EspError> + Send + 'static,
1066 F: FnMut(&[u8]) -> Result<(), EspError> + Send + 'static,
1067 {
1068 Self::new_nonstatic(netif, post_attach_cfg, tx)
1069 }
1070 }
1071
1072 impl<'d, T> EspNetifDriver<'d, T>
1073 where
1074 T: BorrowMut<EspNetif>,
1075 {
1076 pub fn new_nonstatic<P, F>(netif: T, post_attach_cfg: P, tx: F) -> Result<Self, EspError>
1142 where
1143 P: FnMut(&mut EspNetif) -> Result<(), EspError> + Send + 'd,
1144 F: FnMut(&[u8]) -> Result<(), EspError> + Send + 'd,
1145 {
1146 let mut inner = alloc::boxed::Box::new(EspNetifDriverInner {
1147 base: esp_netif_driver_base_t {
1148 netif: netif.borrow().handle(),
1149 post_attach: Some(EspNetifDriverInner::<T>::raw_post_attach),
1150 },
1151 netif,
1152 post_attach_cfg: alloc::boxed::Box::new(post_attach_cfg),
1153 tx: alloc::boxed::Box::new(tx),
1154 });
1155
1156 let inner_ptr = inner.as_mut() as *mut _ as *mut core::ffi::c_void;
1157
1158 if let Some(got_ip_event_id) = inner.netif.borrow()._got_ip_event_id {
1159 esp!(unsafe {
1160 esp_event_handler_register(
1161 IP_EVENT,
1162 got_ip_event_id.get() as _,
1163 Some(esp_netif_action_connected),
1164 inner.netif.borrow().handle() as *mut core::ffi::c_void,
1165 )
1166 })?;
1167 }
1168
1169 if let Some(lost_ip_event_id) = inner.netif.borrow()._lost_ip_event_id {
1170 esp!(unsafe {
1171 esp_event_handler_register(
1172 IP_EVENT,
1173 lost_ip_event_id.get() as _,
1174 Some(esp_netif_action_disconnected),
1175 inner.netif.borrow().handle() as *mut core::ffi::c_void,
1176 )
1177 })?;
1178 }
1179
1180 esp!(unsafe { esp_netif_attach(inner.netif.borrow().handle(), inner_ptr) })?;
1181
1182 Ok(Self {
1183 inner,
1184 started: false,
1185 })
1186 }
1187
1188 pub fn rx(&self, data: &[u8]) -> Result<(), EspError> {
1193 esp!(unsafe {
1194 esp_netif_receive(
1195 self.inner.netif.borrow().handle(),
1196 data.as_ptr() as *mut core::ffi::c_void,
1197 data.len() as _,
1198 core::ptr::null_mut(),
1199 )
1200 })
1201 }
1202
1203 pub fn start(&mut self) -> Result<(), EspError> {
1205 if self.started {
1206 return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
1207 }
1208
1209 unsafe {
1210 esp_netif_action_start(
1211 self.inner.netif.borrow().handle() as *mut core::ffi::c_void,
1212 core::ptr::null_mut(),
1213 0,
1214 core::ptr::null_mut(),
1215 );
1216 }
1217
1218 Ok(())
1219 }
1220
1221 pub fn stop(&mut self) -> Result<(), EspError> {
1223 if !self.started {
1224 return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
1225 }
1226
1227 unsafe {
1228 esp_netif_action_stop(
1229 self.inner.netif.borrow().handle() as *mut core::ffi::c_void,
1230 core::ptr::null_mut(),
1231 0,
1232 core::ptr::null_mut(),
1233 );
1234 }
1235
1236 Ok(())
1237 }
1238
1239 pub fn is_started(&self) -> Result<bool, EspError> {
1241 Ok(self.started)
1242 }
1243
1244 pub fn netif(&self) -> &EspNetif {
1246 self.inner.netif.borrow()
1247 }
1248
1249 pub fn netif_mut(&mut self) -> &mut EspNetif {
1251 self.inner.netif.borrow_mut()
1252 }
1253 }
1254
1255 impl<T> Drop for EspNetifDriver<'_, T>
1256 where
1257 T: BorrowMut<EspNetif>,
1258 {
1259 fn drop(&mut self) {
1260 let _ = self.stop();
1261
1262 if let Some(got_ip_event_id) = self.inner.netif.borrow()._got_ip_event_id {
1263 esp!(unsafe {
1264 esp_event_handler_unregister(
1265 IP_EVENT,
1266 got_ip_event_id.get() as _,
1267 Some(esp_netif_action_connected),
1268 )
1269 })
1270 .unwrap();
1271 }
1272
1273 if let Some(lost_ip_event_id) = self.inner.netif.borrow()._lost_ip_event_id {
1274 esp!(unsafe {
1275 esp_event_handler_unregister(
1276 IP_EVENT,
1277 lost_ip_event_id.get() as _,
1278 Some(esp_netif_action_disconnected),
1279 )
1280 })
1281 .unwrap();
1282 }
1283 }
1284 }
1285
1286 #[repr(C)]
1287 struct EspNetifDriverInner<'d, T>
1288 where
1289 T: BorrowMut<EspNetif>,
1290 {
1291 base: esp_netif_driver_base_t,
1292 netif: T,
1293 #[allow(clippy::type_complexity)]
1294 tx: alloc::boxed::Box<dyn FnMut(&[u8]) -> Result<(), EspError> + Send + 'd>,
1295 #[allow(clippy::type_complexity)]
1296 post_attach_cfg:
1297 alloc::boxed::Box<dyn FnMut(&mut EspNetif) -> Result<(), EspError> + Send + 'd>,
1298 }
1299
1300 impl<T> EspNetifDriverInner<'_, T>
1301 where
1302 T: BorrowMut<EspNetif>,
1303 {
1304 fn post_attach(&mut self, netif_handle: *mut esp_netif_obj) -> Result<(), EspError> {
1305 let driver_ifconfig = esp_netif_driver_ifconfig_t {
1306 transmit: Some(Self::raw_tx),
1307 handle: self as *mut _ as *mut core::ffi::c_void,
1308 ..Default::default()
1309 };
1310
1311 debug!("Post attach ifconfig: {driver_ifconfig:?}");
1312
1313 esp!(unsafe { esp_netif_set_driver_config(netif_handle, &driver_ifconfig) })?;
1316
1317 (self.post_attach_cfg)(self.netif.borrow_mut())?;
1318
1319 Ok(())
1320 }
1321
1322 fn tx(&mut self, data: &[u8]) -> Result<(), EspError> {
1323 (self.tx)(data)
1324 }
1325
1326 unsafe extern "C" fn raw_tx(
1327 h: *mut core::ffi::c_void,
1328 buffer: *mut core::ffi::c_void,
1329 len: usize,
1330 ) -> i32 {
1331 let this = unsafe { (h as *mut Self).as_mut() }.unwrap();
1332 let data = core::slice::from_raw_parts(buffer as *mut u8, len);
1333
1334 #[allow(clippy::let_and_return)]
1335 let result = match this.tx(data) {
1336 Ok(_) => ESP_OK,
1337 Err(e) => e.code(),
1338 };
1339
1340 result
1345 }
1346
1347 unsafe extern "C" fn raw_post_attach(
1348 netif: *mut esp_netif_obj,
1349 args: *mut core::ffi::c_void,
1350 ) -> i32 {
1351 let this = { (args as *mut Self).as_mut() }.unwrap();
1352 match this.post_attach(netif) {
1353 Ok(_) => ESP_OK,
1354 Err(e) => e.code(),
1355 }
1356 }
1357 }
1358}
1359
1360#[cfg(esp_idf_lwip_ppp_support)]
1361mod ppp {
1362 use core::ffi::{self, CStr};
1363
1364 use enumset::{EnumSet, EnumSetType};
1365
1366 use crate::eventloop::{EspEventDeserializer, EspEventSource};
1367 use crate::handle::RawHandle;
1368 use crate::sys::*;
1369
1370 #[derive(Copy, Clone, Debug)]
1372 pub enum PppEvent {
1373 NoError,
1375 ParameterError,
1377 OpenError,
1379 DeviceError,
1381 AllocError,
1383 UserError,
1385 DisconnectError,
1387 AuthFailError,
1389 ProtocolError,
1391 PeerDeadError,
1393 IdleTimeoutError,
1395 MaxConnectTimeoutError,
1397 LoopbackError,
1399 PhaseDead,
1400 PhaseMaster,
1401 PhaseHoldoff,
1402 PhaseInitialize,
1403 PhaseSerialConnection,
1404 PhaseDormant,
1405 PhaseEstablish,
1406 PhaseAuthenticate,
1407 PhaseCallback,
1408 PhaseNetwork,
1409 PhaseRunning,
1410 PhaseTerminate,
1411 PhaseDisconnect,
1412 PhaseFailed,
1413
1414 Other(i32),
1420 }
1421
1422 unsafe impl EspEventSource for PppEvent {
1423 fn source() -> Option<&'static core::ffi::CStr> {
1424 Some(unsafe { ffi::CStr::from_ptr(NETIF_PPP_STATUS) })
1425 }
1426 }
1427
1428 impl EspEventDeserializer for PppEvent {
1429 type Data<'a> = PppEvent;
1430
1431 #[allow(non_upper_case_globals, non_snake_case)]
1432 fn deserialize<'a>(data: &crate::eventloop::EspEvent<'a>) -> Self::Data<'a> {
1433 let event_id = data.event_id as u32;
1434
1435 match event_id {
1436 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORNONE => PppEvent::NoError,
1437 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPARAM => PppEvent::ParameterError,
1438 esp_netif_ppp_status_event_t_NETIF_PPP_ERROROPEN => PppEvent::OpenError,
1439 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORDEVICE => PppEvent::DeviceError,
1440 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORALLOC => PppEvent::AllocError,
1441 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORUSER => PppEvent::UserError,
1442 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORCONNECT => PppEvent::DisconnectError,
1443 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORAUTHFAIL => PppEvent::AuthFailError,
1444 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPROTOCOL => PppEvent::ProtocolError,
1445 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPEERDEAD => PppEvent::PeerDeadError,
1446 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORIDLETIMEOUT => {
1447 PppEvent::IdleTimeoutError
1448 }
1449 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORCONNECTTIME => {
1450 PppEvent::MaxConnectTimeoutError
1451 }
1452 esp_netif_ppp_status_event_t_NETIF_PPP_ERRORLOOPBACK => PppEvent::LoopbackError,
1453 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DEAD => PppEvent::PhaseDead,
1454 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_MASTER => PppEvent::PhaseMaster,
1455 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_HOLDOFF => PppEvent::PhaseHoldoff,
1456 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_INITIALIZE => {
1457 PppEvent::PhaseInitialize
1458 }
1459 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_SERIALCONN => {
1460 PppEvent::PhaseSerialConnection
1461 }
1462 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DORMANT => PppEvent::PhaseDormant,
1463 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_ESTABLISH => PppEvent::PhaseEstablish,
1464 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_AUTHENTICATE => {
1465 PppEvent::PhaseAuthenticate
1466 }
1467 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_CALLBACK => PppEvent::PhaseCallback,
1468 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_NETWORK => PppEvent::PhaseNetwork,
1469 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_RUNNING => PppEvent::PhaseRunning,
1470 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_TERMINATE => PppEvent::PhaseTerminate,
1471 esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DISCONNECT => {
1472 PppEvent::PhaseDisconnect
1473 }
1474 esp_netif_ppp_status_event_t_NETIF_PPP_CONNECT_FAILED => PppEvent::PhaseFailed,
1475 _ => {
1476 ::log::warn!("PppEvent: unknown event ID {event_id}, ignoring");
1477 PppEvent::Other(event_id as i32)
1478 }
1479 }
1480 }
1481 }
1482
1483 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
1484 pub struct PppConfiguration {
1485 pub phase_events_enabled: bool,
1487 pub error_events_enabled: bool,
1489 #[cfg(esp_idf_lwip_enable_lcp_echo)]
1494 pub lcp_echo_disabled: bool,
1495 #[cfg(esp_idf_lwip_ppp_server_support)]
1497 our_ip4_addr: core::net::Ipv4Addr,
1498 #[cfg(esp_idf_lwip_ppp_server_support)]
1500 their_ip4_addr: core::net::Ipv4Addr,
1501 }
1502
1503 impl PppConfiguration {
1504 pub const fn new() -> Self {
1505 Self {
1506 phase_events_enabled: true,
1507 error_events_enabled: true,
1508 #[cfg(esp_idf_lwip_enable_lcp_echo)]
1509 lcp_echo_disabled: false,
1510 #[cfg(esp_idf_lwip_ppp_server_support)]
1511 our_ip4_addr: core::net::Ipv4Addr::UNSPECIFIED,
1512 #[cfg(esp_idf_lwip_ppp_server_support)]
1513 their_ip4_addr: core::net::Ipv4Addr::UNSPECIFIED,
1514 }
1515 }
1516 }
1517
1518 impl Default for PppConfiguration {
1519 fn default() -> Self {
1520 Self::new()
1521 }
1522 }
1523
1524 impl From<esp_netif_ppp_config_t> for PppConfiguration {
1525 fn from(cfg: esp_netif_ppp_config_t) -> Self {
1526 Self {
1527 phase_events_enabled: cfg.ppp_phase_event_enabled,
1528 error_events_enabled: cfg.ppp_error_event_enabled,
1529 #[cfg(esp_idf_lwip_enable_lcp_echo)]
1530 lcp_echo_disabled: cfg.lcp_echo_disabled,
1531 #[cfg(esp_idf_lwip_ppp_server_support)]
1532 our_ip4_addr: Newtype::<core::net::Ipv4Addr>::from(cfg.our_ip4_addr),
1533 #[cfg(esp_idf_lwip_ppp_server_support)]
1534 their_ip4_addr: Newtype::<core::net::Ipv4Addr>::from(cfg.their_ip4_addr),
1535 }
1536 }
1537 }
1538
1539 impl From<&PppConfiguration> for esp_netif_ppp_config_t {
1540 fn from(cfg: &PppConfiguration) -> Self {
1541 Self {
1542 ppp_phase_event_enabled: cfg.phase_events_enabled,
1543 ppp_error_event_enabled: cfg.error_events_enabled,
1544 #[cfg(esp_idf_lwip_enable_lcp_echo)]
1545 lcp_echo_disabled: cfg.lcp_echo_disabled,
1546 #[cfg(esp_idf_lwip_ppp_server_support)]
1547 our_ip4_addr: Newtype::<esp_ip4_addr_t>::from(cfg.our_ip4_addr),
1548 #[cfg(esp_idf_lwip_ppp_server_support)]
1549 their_ip4_addr: Newtype::<esp_ip4_addr_t>::from(cfg.their_ip4_addr),
1550 }
1551 }
1552 }
1553
1554 #[derive(Debug, EnumSetType)]
1555 #[enumset(repr = "u32")]
1556 pub enum PppAuthentication {
1557 Pap,
1558 Chap,
1559 MsChap,
1560 MsChapV2,
1561 Eap,
1562 }
1563
1564 impl super::EspNetif {
1566 #[cfg(not(esp_idf_version_major = "4"))]
1568 pub fn get_ppp_conf(&self) -> Result<PppConfiguration, EspError> {
1569 let mut ppp_config = Default::default();
1570
1571 esp!(unsafe { esp_netif_ppp_get_params(self.handle(), &mut ppp_config) })?;
1572
1573 Ok(ppp_config.into())
1574 }
1575
1576 pub fn set_ppp_conf(&mut self, conf: &PppConfiguration) -> Result<(), EspError> {
1578 let ppp_config: esp_netif_ppp_config_t = conf.into();
1579
1580 esp!(unsafe { esp_netif_ppp_set_params(self.handle(), &ppp_config) })
1581 }
1582
1583 pub fn set_ppp_auth(
1589 &mut self,
1590 auth: EnumSet<PppAuthentication>,
1591 username: &CStr,
1592 password: &CStr,
1593 ) -> Result<(), EspError> {
1594 esp!(unsafe {
1595 esp_netif_ppp_set_auth(
1596 self.handle(),
1597 auth.as_repr(),
1598 username.as_ptr() as _,
1599 password.as_ptr() as _,
1600 )
1601 })
1602 }
1603 }
1604}
1605
1606pub mod asynch {
1607 use crate::sys::EspError;
1608
1609 pub trait NetifStatus {
1610 async fn is_up(&self) -> Result<bool, EspError>;
1611 }
1612
1613 impl<T> NetifStatus for &T
1614 where
1615 T: NetifStatus,
1616 {
1617 async fn is_up(&self) -> Result<bool, EspError> {
1618 (**self).is_up().await
1619 }
1620 }
1621
1622 impl<T> NetifStatus for &mut T
1623 where
1624 T: NetifStatus,
1625 {
1626 async fn is_up(&self) -> Result<bool, EspError> {
1627 (**self).is_up().await
1628 }
1629 }
1630
1631 impl NetifStatus for super::EspNetif {
1632 async fn is_up(&self) -> Result<bool, EspError> {
1633 super::EspNetif::is_up(self)
1634 }
1635 }
1636
1637 #[cfg(all(feature = "alloc", esp_idf_comp_esp_timer_enabled))]
1638 impl<T> NetifStatus for super::AsyncNetif<T>
1639 where
1640 T: super::NetifStatus,
1641 {
1642 async fn is_up(&self) -> Result<bool, EspError> {
1643 super::AsyncNetif::is_up(self)
1644 }
1645 }
1646}