Skip to content

Commit

Permalink
Fix WPS regression and cred conversion (#379)
Browse files Browse the repository at this point in the history
* Fix WPS regression and cred conversion

Fixes #337
Also fixes the conversion of ssid/password in the config
to no longer assume 0 termination - this lead to problems
when routers send a 64 byte access token to us instead of a password

* Fix return type

* Fix array_to_heapless

* More fixes for max length wifi credentials

* Fix for non_std

* Use array_to_heapless in another instance
  • Loading branch information
torkleyy authored May 16, 2024
1 parent af2aae4 commit 053fb48
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 24 deletions.
26 changes: 26 additions & 0 deletions src/private/cstr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ pub fn set_str(buf: &mut [u8], s: &str) -> Result<(), EspError> {
Ok(())
}

pub fn set_str_no_termination_requirement(buf: &mut [u8], s: &str) -> Result<(), EspError> {
if s.len() > buf.len() {
return Err(EspError::from_infallible::<ESP_ERR_INVALID_SIZE>());
}

buf[..s.len()].copy_from_slice(s.as_bytes());
if buf.len() != s.len() {
buf[s.len()] = 0;
}

Ok(())
}

pub fn c_char_to_u8_slice_mut(s: &mut [c_char]) -> &mut [u8] {
let s_ptr = unsafe { s.as_mut_ptr() as *mut u8 };
unsafe { core::slice::from_raw_parts_mut(s_ptr, s.len()) }
Expand All @@ -41,6 +54,19 @@ pub fn from_cstr(buf: &[u8]) -> &str {
from_cstr_fallible(buf).unwrap()
}

/// Convert buffer of characters to heapless string, allowing either
/// the full buffer (without terminating 0) or just a part of it (terminated by 0)
pub fn array_to_heapless_string_failible<const N: usize>(
arr: [u8; N],
) -> Result<heapless::String<N>, Utf8Error> {
let len = arr.iter().position(|e| *e == 0).unwrap_or(N);
heapless::String::from_utf8(heapless::Vec::from_slice(&arr[0..len]).unwrap())
}

pub fn array_to_heapless_string<const N: usize>(arr: [u8; N]) -> heapless::String<N> {
array_to_heapless_string_failible(arr).unwrap()
}

#[cfg(feature = "alloc")]
pub struct RawCstrs(alloc::vec::Vec<CString>);

Expand Down
43 changes: 19 additions & 24 deletions src/wifi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ impl TryFrom<&ClientConfiguration> for Newtype<wifi_sta_config_t> {
..Default::default()
};

set_str(&mut result.ssid, conf.ssid.as_ref())?;
set_str(&mut result.password, conf.password.as_ref())?;
set_str_no_termination_requirement(&mut result.ssid, conf.ssid.as_ref())?;
set_str_no_termination_requirement(&mut result.password, conf.password.as_ref())?;

Ok(Newtype(result))
}
Expand All @@ -207,14 +207,14 @@ impl TryFrom<&ClientConfiguration> for Newtype<wifi_sta_config_t> {
impl From<Newtype<wifi_sta_config_t>> for ClientConfiguration {
fn from(conf: Newtype<wifi_sta_config_t>) -> Self {
Self {
ssid: from_cstr(&conf.0.ssid).try_into().unwrap(),
ssid: array_to_heapless_string(conf.0.ssid),
bssid: if conf.0.bssid_set {
Some(conf.0.bssid)
} else {
None
},
auth_method: Option::<AuthMethod>::from(Newtype(conf.0.threshold.authmode)).unwrap(),
password: from_cstr(&conf.0.password).try_into().unwrap(),
password: array_to_heapless_string(conf.0.password),
channel: if conf.0.channel != 0 {
Some(conf.0.channel)
} else {
Expand Down Expand Up @@ -275,7 +275,7 @@ impl From<Newtype<wifi_ap_config_t>> for AccessPointConfiguration {
fn from(conf: Newtype<wifi_ap_config_t>) -> Self {
Self {
ssid: if conf.0.ssid_len == 0 {
from_cstr(&conf.0.ssid).try_into().unwrap()
Default::default()
} else {
unsafe {
core::str::from_utf8_unchecked(&conf.0.ssid[0..conf.0.ssid_len as usize])
Expand All @@ -288,7 +288,7 @@ impl From<Newtype<wifi_ap_config_t>> for AccessPointConfiguration {
secondary_channel: None,
auth_method: Option::<AuthMethod>::from(Newtype(conf.0.authmode)).unwrap(),
protocols: EnumSet::<Protocol>::empty(), // TODO
password: from_cstr(&conf.0.password).try_into().unwrap(),
password: array_to_heapless_string(conf.0.password),
max_connections: conf.0.max_connection as u16,
}
}
Expand Down Expand Up @@ -2122,30 +2122,25 @@ impl<'a> EspEventDeserializer for WifiEvent<'a> {
wifi_event_t_WIFI_EVENT_STA_DISCONNECTED => WifiEvent::StaDisconnected,
wifi_event_t_WIFI_EVENT_STA_AUTHMODE_CHANGE => WifiEvent::StaAuthmodeChanged,
wifi_event_t_WIFI_EVENT_STA_WPS_ER_SUCCESS => {
let payload = unsafe {
(data.payload.unwrap() as *const _ as *const wifi_event_sta_wps_er_success_t)
.as_ref()
};

let credentials = payload
.map(|payload| &payload.ap_cred[..payload.ap_cred_cnt as _])
let credentials: &[wifi_event_sta_wps_er_success_t__bindgen_ty_1] = data
.payload
.map(|x| x as *const _ as *const wifi_event_sta_wps_er_success_t)
.and_then(|x| unsafe { x.as_ref() })
.map(|x| &x.ap_cred[0..x.ap_cred_cnt as usize])
.unwrap_or(&[]);
// SAFETY: transparent representation of target type
let credentials: &[WpsCredentialsRef] =
unsafe { core::mem::transmute(credentials) };

WifiEvent::StaWpsSuccess(unsafe {
core::mem::transmute::<
&[wifi_event_sta_wps_er_success_t__bindgen_ty_1],
&[WpsCredentialsRef],
>(credentials)
})
WifiEvent::StaWpsSuccess(credentials)
}
wifi_event_t_WIFI_EVENT_STA_WPS_ER_FAILED => WifiEvent::StaWpsFailed,
wifi_event_t_WIFI_EVENT_STA_WPS_ER_TIMEOUT => WifiEvent::StaWpsTimeout,
wifi_event_t_WIFI_EVENT_STA_WPS_ER_PIN => {
let payload = unsafe {
(data.payload.unwrap() as *const _ as *const wifi_event_sta_wps_er_pin_t)
.as_ref()
};
let pin = payload
let pin = data
.payload
.map(|x| x as *const _ as *const wifi_event_sta_wps_er_pin_t)
.and_then(|x| unsafe { x.as_ref() })
.and_then(|x| core::str::from_utf8(&x.pin_code).ok())
.and_then(|x| x.parse().ok());
WifiEvent::StaWpsPin(pin)
Expand Down

0 comments on commit 053fb48

Please sign in to comment.