use crate::StackError;
use arrayvec::ArrayString;
use super::constants::{
AuthType, WifiChannel, MAX_HOST_NAME_LEN, MAX_PSK_KEY_LEN, MAX_S802_PASSWORD_LEN,
MAX_S802_USERNAME_LEN, MAX_SSID_LEN, MAX_WEP_KEY_LEN, MIN_PSK_KEY_LEN,
};
#[cfg(feature = "experimental-ecc")]
use super::constants::{EccCurveType, EccRequestType};
#[cfg(feature = "wep")]
use super::constants::{WepKeyIndex, MIN_WEP_KEY_LEN};
use core::net::Ipv4Addr;
const DEFAULT_AP_IP: u32 = 0xC0A80101;
#[cfg(feature = "experimental-ecc")]
const ECC_POINT_MAX_SIZE: usize = 32;
const MAX_OCTETS_IN_MAC_ADDRESS: usize = 6;
pub type HostName = ArrayString<MAX_HOST_NAME_LEN>;
pub type Ssid = ArrayString<MAX_SSID_LEN>;
pub type WpaKey = ArrayString<MAX_PSK_KEY_LEN>;
pub type WepKey = ArrayString<MAX_WEP_KEY_LEN>;
pub type S8Username = ArrayString<MAX_S802_USERNAME_LEN>;
pub type S8Password = ArrayString<MAX_S802_PASSWORD_LEN>;
#[cfg(feature = "experimental-ecc")]
pub(crate) type EcdsaVerifyInfo = u32;
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Credentials {
Open = 1,
WpaPSK(WpaKey) = 2,
#[cfg(feature = "wep")]
Wep(WepKey, WepKeyIndex) = 3,
S802_1X(S8Username, S8Password) = 4,
}
#[derive(PartialEq, Eq)]
pub enum SocketOptions {
Tcp(TcpSockOpts),
Udp(UdpSockOpts),
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum UdpSockOpts {
ReceiveTimeout(u32) = 0xff,
SetUdpSendCallback(bool) = 0x00,
JoinMulticast(Ipv4Addr) = 0x01,
LeaveMulticast(Ipv4Addr) = 0x02,
}
#[repr(u8)]
#[derive(PartialEq, Eq)]
pub enum TcpSockOpts {
ReceiveTimeout(u32) = 0xff,
#[cfg(feature = "ssl")]
Ssl(SslSockOpts) = 0xfe,
}
#[cfg(feature = "ssl")]
#[repr(u8)]
#[derive(PartialEq, Eq)]
pub enum SslSockOpts {
Config(SslSockConfig, bool),
SetSni(HostName) = 0x02,
}
#[cfg(feature = "ssl")]
#[repr(u8)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum SslSockConfig {
EnableSSL = 0x21, BypassX509Verification = 0x02,
EnableSessionCache = 0x10,
EnableSniValidation = 0x40,
}
pub struct ProvisioningInfo {
pub ssid: Ssid,
pub key: Credentials,
pub(crate) status: bool,
}
#[derive(Debug, PartialEq, Eq)]
pub struct AccessPoint<'a> {
pub ssid: &'a Ssid,
pub key: Credentials,
pub channel: WifiChannel,
pub ssid_hidden: bool,
pub ip: Ipv4Addr,
}
#[cfg(feature = "experimental-ecc")]
#[derive(Default)]
pub struct EccPoint {
pub x_pos: [u8; ECC_POINT_MAX_SIZE],
pub y_pos: [u8; ECC_POINT_MAX_SIZE],
pub point_size: u16,
pub private_key_id: u16,
}
#[cfg(feature = "experimental-ecc")]
#[derive(Default)]
pub struct EcdhInfo {
pub ecc_point: EccPoint,
pub private_key: [u8; ECC_POINT_MAX_SIZE],
}
#[cfg(feature = "experimental-ecc")]
#[derive(Default)]
pub struct EcdsaSignInfo {
pub curve_type: EccCurveType,
pub hash_size: u16,
}
#[cfg(feature = "experimental-ecc")]
#[derive(Default)]
pub struct EccInfo {
pub req: EccRequestType,
pub status: u16,
pub user_data: u32,
pub seq_num: u32,
}
#[cfg(feature = "experimental-ecc")]
#[derive(Default)]
pub(crate) struct EccRequest {
pub hif_reg: u32,
pub ecc_info: EccInfo,
pub ecdh_info: Option<EcdhInfo>,
pub ecdsa_sign_info: Option<EcdsaSignInfo>,
pub ecdsa_verify_info: Option<EcdsaVerifyInfo>,
}
#[cfg(feature = "ssl")]
#[derive(Default)]
pub(crate) struct SslCallbackInfo {
pub(crate) cipher_suite_bitmap: Option<Option<u32>>,
#[cfg(feature = "experimental-ecc")]
pub(crate) ecc_req: Option<EccRequest>,
}
pub struct MacAddress {
mac: [u8; MAX_OCTETS_IN_MAC_ADDRESS],
}
#[cfg(feature = "ethernet")]
pub(crate) struct EthernetRxInfo {
pub(crate) packet_size: u16,
pub(crate) data_offset: u16,
pub(crate) hif_address: u32,
}
impl From<Credentials> for AuthType {
fn from(cred: Credentials) -> Self {
match cred {
Credentials::Open => Self::Open,
Credentials::WpaPSK(_) => Self::WpaPSK,
#[cfg(feature = "wep")]
Credentials::Wep(_, _) => Self::WEP,
Credentials::S802_1X(_, _) => Self::S802_1X,
}
}
}
impl From<Credentials> for u8 {
fn from(val: Credentials) -> Self {
match val {
Credentials::Open => 1,
Credentials::WpaPSK(_) => 2,
#[cfg(feature = "wep")]
Credentials::Wep(_, _) => 3,
Credentials::S802_1X(_, _) => 4,
}
}
}
impl Credentials {
pub fn key_len(&self) -> usize {
match self {
Credentials::Open => 0,
#[cfg(feature = "wep")]
Credentials::Wep(key, _) => key.len(),
Credentials::WpaPSK(key) => key.len(),
Credentials::S802_1X(_, key) => key.len(),
}
}
pub fn from_wpa(password: &str) -> Result<Self, StackError> {
if password.len() < MIN_PSK_KEY_LEN {
return Err(StackError::InvalidParameters);
}
WpaKey::from(password)
.map(Self::WpaPSK)
.map_err(|_| StackError::InvalidParameters)
}
pub fn from_s802(username: &str, password: &str) -> Result<Self, StackError> {
let username = S8Username::from(username).map_err(|_| StackError::InvalidParameters)?;
let password = S8Password::from(password).map_err(|_| StackError::InvalidParameters)?;
Ok(Self::S802_1X(username, password))
}
#[cfg(feature = "wep")]
pub fn from_wep(key: &str, key_index: WepKeyIndex) -> Result<Self, StackError> {
if key.len() != MAX_WEP_KEY_LEN && key.len() != MIN_WEP_KEY_LEN {
return Err(StackError::InvalidParameters);
}
WepKey::from(key)
.map(|key| Credentials::Wep(key, key_index))
.map_err(|_| StackError::InvalidParameters)
}
}
impl From<UdpSockOpts> for u8 {
fn from(value: UdpSockOpts) -> Self {
match value {
UdpSockOpts::SetUdpSendCallback(_) => 0x00,
UdpSockOpts::JoinMulticast(_) => 0x01,
UdpSockOpts::LeaveMulticast(_) => 0x02,
UdpSockOpts::ReceiveTimeout(_) => 0xff,
}
}
}
impl UdpSockOpts {
pub fn get_value(&self) -> u32 {
match self {
UdpSockOpts::ReceiveTimeout(val) => *val,
UdpSockOpts::SetUdpSendCallback(val) => *val as u32,
UdpSockOpts::JoinMulticast(val) | UdpSockOpts::LeaveMulticast(val) => {
u32::from_le_bytes(val.to_bits().to_be_bytes())
}
}
}
}
impl From<TcpSockOpts> for u8 {
fn from(value: TcpSockOpts) -> Self {
match value {
#[cfg(feature = "ssl")]
TcpSockOpts::Ssl(_) => 0xfe,
TcpSockOpts::ReceiveTimeout(_) => 0xff,
}
}
}
impl TcpSockOpts {
pub fn get_value(&self) -> u32 {
match self {
TcpSockOpts::ReceiveTimeout(val) => *val,
#[cfg(feature = "ssl")]
TcpSockOpts::Ssl(_) => 0xfe,
}
}
}
#[cfg(feature = "ssl")]
impl From<SslSockOpts> for u8 {
fn from(value: SslSockOpts) -> Self {
match value {
SslSockOpts::Config(cfg, _) => cfg.into(),
SslSockOpts::SetSni(_) => 0x02,
}
}
}
#[cfg(feature = "ssl")]
impl From<&SslSockOpts> for u8 {
fn from(value: &SslSockOpts) -> Self {
match value {
SslSockOpts::Config(cfg, _) => (*cfg).into(),
SslSockOpts::SetSni(_) => 0x02,
}
}
}
#[cfg(feature = "ssl")]
impl From<SslSockConfig> for u8 {
fn from(value: SslSockConfig) -> Self {
value as Self
}
}
#[cfg(feature = "ssl")]
impl SslSockOpts {
pub(crate) fn get_sni_value(&self) -> Result<&HostName, StackError> {
match self {
SslSockOpts::SetSni(hostname) => Ok(hostname),
_ => Err(StackError::InvalidParameters),
}
}
}
impl SocketOptions {
pub fn join_multicast_v4(addr: Ipv4Addr) -> Self {
Self::Udp(UdpSockOpts::JoinMulticast(addr))
}
pub fn leave_multicast_v4(addr: Ipv4Addr) -> Self {
Self::Udp(UdpSockOpts::LeaveMulticast(addr))
}
pub fn set_udp_send_callback(status: bool) -> Self {
Self::Udp(UdpSockOpts::SetUdpSendCallback(status))
}
pub fn set_udp_receive_timeout(timeout: u32) -> Self {
Self::Udp(UdpSockOpts::ReceiveTimeout(timeout))
}
pub fn set_tcp_receive_timeout(timeout: u32) -> Self {
Self::Tcp(TcpSockOpts::ReceiveTimeout(timeout))
}
#[cfg(feature = "ssl")]
pub fn set_sni(hostname: &str) -> Result<Self, StackError> {
let host = HostName::from(hostname).map_err(|_| StackError::InvalidParameters)?;
Ok(Self::Tcp(TcpSockOpts::Ssl(SslSockOpts::SetSni(host))))
}
#[cfg(feature = "ssl")]
pub fn config_ssl(cfg: SslSockConfig, enable: bool) -> Self {
Self::Tcp(TcpSockOpts::Ssl(SslSockOpts::Config(cfg, enable)))
}
}
impl<'a> AccessPoint<'a> {
pub fn new(
ssid: &'a Ssid,
key: Credentials,
channel: WifiChannel,
ssid_hidden: bool,
ip: Ipv4Addr,
) -> Result<Self, StackError> {
let octets = ip.octets();
let auth = <Credentials as Into<AuthType>>::into(key);
if !((1..100).contains(&octets[3])) {
return Err(StackError::InvalidParameters);
}
if auth == AuthType::S802_1X {
return Err(StackError::InvalidParameters);
}
Ok(Self {
ssid,
key,
channel,
ssid_hidden,
ip: Ipv4Addr::from(octets),
})
}
pub fn open(ssid: &'a Ssid) -> Self {
Self {
ssid,
key: Credentials::Open,
channel: WifiChannel::Channel1,
ssid_hidden: false,
ip: Ipv4Addr::from_bits(DEFAULT_AP_IP),
}
}
#[cfg(feature = "wep")]
pub fn wep(ssid: &'a Ssid, key: &'a WepKey, key_index: WepKeyIndex) -> Self {
Self {
ssid,
key: Credentials::Wep(*key, key_index),
channel: WifiChannel::Channel1,
ssid_hidden: false,
ip: Ipv4Addr::from_bits(DEFAULT_AP_IP),
}
}
pub fn wpa(ssid: &'a Ssid, key: &'a WpaKey) -> Self {
Self {
ssid,
key: Credentials::WpaPSK(*key),
channel: WifiChannel::Channel1,
ssid_hidden: false,
ip: Ipv4Addr::from_bits(DEFAULT_AP_IP),
}
}
pub fn set_ip(&mut self, ip: Ipv4Addr) -> Result<(), StackError> {
let octets = ip.octets();
if !((1..100).contains(&octets[3])) {
return Err(StackError::InvalidParameters);
}
self.ip = Ipv4Addr::from(octets);
Ok(())
}
pub fn set_channel(&mut self, channel: WifiChannel) {
self.channel = channel;
}
pub fn set_ssid_hidden(&mut self, hidden: bool) {
self.ssid_hidden = hidden;
}
}
impl MacAddress {
pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddress {
Self {
mac: [a, b, c, d, e, f],
}
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, StackError> {
if bytes.len() != MAX_OCTETS_IN_MAC_ADDRESS {
return Err(StackError::InvalidParameters);
}
let mut mac = [0u8; MAX_OCTETS_IN_MAC_ADDRESS];
mac.copy_from_slice(bytes);
Ok(Self { mac })
}
pub fn empty() -> Self {
Self {
mac: [0u8; MAX_OCTETS_IN_MAC_ADDRESS],
}
}
#[inline]
pub fn octets(&self) -> [u8; MAX_OCTETS_IN_MAC_ADDRESS] {
self.mac
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.mac
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.mac
}
}
#[cfg(feature = "log")]
impl core::fmt::Display for MacAddress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.mac[0], self.mac[1], self.mac[2], self.mac[3], self.mac[4], self.mac[5]
)
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for MacAddress {
fn format(&self, f: defmt::Formatter) {
defmt::write!(
f,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.mac[0],
self.mac[1],
self.mac[2],
self.mac[3],
self.mac[4],
self.mac[5]
)
}
}
#[cfg(test)]
mod tests {
use core::str::FromStr;
use super::*;
#[test]
fn test_ap_set_channel() {
let ssid = Ssid::from("test").unwrap();
let mut ap = AccessPoint::open(&ssid);
assert_eq!(ap.channel, WifiChannel::Channel1);
ap.set_channel(WifiChannel::Channel2);
assert_eq!(ap.channel, WifiChannel::Channel2);
}
#[test]
fn test_ap_set_ip_fail() {
let ssid = Ssid::from("test").unwrap();
let psk = WpaKey::from("test_key").unwrap();
let mut ap = AccessPoint::wpa(&ssid, &psk);
let ip = Ipv4Addr::new(192, 168, 1, 100);
assert_eq!(ap.ip, Ipv4Addr::from_bits(DEFAULT_AP_IP));
let result = ap.set_ip(ip);
assert_eq!(result, Err(StackError::InvalidParameters))
}
#[test]
fn test_ap_set_ip_success() {
let ssid = Ssid::from("test").unwrap();
let psk = WpaKey::from("test_key").unwrap();
let mut ap = AccessPoint::wpa(&ssid, &psk);
let ip = Ipv4Addr::new(192, 168, 1, 1);
assert_eq!(ap.ip, Ipv4Addr::from_bits(DEFAULT_AP_IP));
let result = ap.set_ip(ip);
assert!(result.is_ok());
}
#[test]
fn test_ap_config_fail() {
let ssid = Ssid::from("test").unwrap();
let psk = WpaKey::from("test_key").unwrap();
let ap = AccessPoint::new(
&ssid,
Credentials::WpaPSK(psk),
WifiChannel::Channel1,
false,
Ipv4Addr::new(192, 168, 1, 100),
);
assert_eq!(ap, Err(StackError::InvalidParameters));
}
#[test]
fn test_ap_config_success() {
let ssid = Ssid::from("test").unwrap();
let psk = WpaKey::from("test_key").unwrap();
let ap = AccessPoint::new(
&ssid,
Credentials::WpaPSK(psk),
WifiChannel::Channel1,
false,
Ipv4Addr::new(192, 168, 1, 1),
);
assert!(ap.is_ok());
}
#[test]
fn test_ap_config_enterprise_fail() {
let ssid = Ssid::from("test").unwrap();
let username = S8Username::from("username").unwrap();
let password = S8Password::from("password").unwrap();
let ap = AccessPoint::new(
&ssid,
Credentials::S802_1X(username, password),
WifiChannel::Channel1,
false,
Ipv4Addr::new(192, 168, 1, 1),
);
assert_eq!(ap, Err(StackError::InvalidParameters));
}
#[test]
fn test_ssid_visibility() {
let ssid = Ssid::from("test").unwrap();
let mut ap = AccessPoint::open(&ssid);
assert_eq!(ap.ssid_hidden, false);
ap.set_ssid_hidden(true);
assert_eq!(ap.ssid_hidden, true);
}
#[test]
fn test_wpa_credentials_with_short_password() {
let result = Credentials::from_wpa("pass");
assert_eq!(result.err(), Some(StackError::InvalidParameters));
}
#[test]
fn test_wpa_credentials_with_long_password() {
let long_password = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let result = Credentials::from_wpa(long_password);
assert!(result.is_err());
}
#[test]
fn test_wpa_credentials_with_valid_password() {
let result = Credentials::from_wpa("ABCDEFGHIJKLM");
assert!(result.is_ok());
}
#[test]
fn test_s802_credentials_invalid_username() {
let username = "abcdefghijklmnopqrst123";
let password = "abcdefghijklmnopqrstuvwxyz1234567890ABCD";
let result = Credentials::from_s802(username, password);
assert_eq!(result.err(), Some(StackError::InvalidParameters));
}
#[test]
fn test_s802_credentials_invalid_password() {
let username = "abcdefghijklmnopqrst";
let password = "abcdefghijklmnopqrstuvwxyz1234567890ABC123D";
let result = Credentials::from_s802(username, password);
assert_eq!(result.err(), Some(StackError::InvalidParameters));
}
#[test]
fn test_s802_credentials_valid() {
let username = "abcdefghijklmnopqrst";
let password = "abcdefghijklmnopqrstuvwxyz1234567890ABCD";
let result = Credentials::from_s802(username, password);
assert!(result.is_ok());
}
#[test]
fn test_s802_key_len() {
let username = "abcdefghijklmnopqrst";
let password = "abcdefghijklmnopqrstuvwxyz1234567890ABCD";
let result = Credentials::from_s802(username, password);
assert!(result.is_ok());
assert_eq!(result.unwrap().key_len(), password.len());
}
#[test]
fn test_s802_auth_type() {
let username = "abcdefghijklmnopqrst";
let password = "abcdefghijklmnopqrstuvwxyz1234567890ABCD";
let result = Credentials::from_s802(username, password);
assert!(result.is_ok());
let s802_auth: u8 = result.unwrap().into();
assert_eq!(s802_auth, <AuthType as Into<u8>>::into(AuthType::S802_1X));
}
#[cfg(feature = "wep")]
#[test]
fn test_wep_credentials_with_small_key() {
let result = Credentials::from_wep("ABCDEFG", WepKeyIndex::Key1);
assert!(result.is_err());
}
#[cfg(feature = "wep")]
#[test]
fn test_wep_credentials_with_large_key() {
let long_password = "ABCDEFGlmnopqrstuvwxyz0123456789+/";
let result = Credentials::from_wep(long_password, WepKeyIndex::Key2);
assert!(result.is_err());
}
#[cfg(feature = "wep")]
#[test]
fn test_wep_credentials_with_104_bit_key() {
let key = "0123456789ABCDEF0123456789";
let result = Credentials::from_wep(key, WepKeyIndex::Key3);
assert!(result.is_ok());
}
#[test]
fn test_sock_opts_get_join_multicast_value_success() {
let test_value: u32 = 0x101a8c0;
let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
let sock_opt = SocketOptions::join_multicast_v4(addr);
if let SocketOptions::Udp(opt) = sock_opt {
assert_eq!(test_value, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_join_multicast_value_fail() {
let test_value: u32 = 0xc0a80101;
let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
let sock_opt = SocketOptions::join_multicast_v4(addr);
if let SocketOptions::Udp(opt) = sock_opt {
assert_ne!(test_value, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_leave_multicast_value_success() {
let test_value: u32 = 0x101a8c0;
let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
let sock_opt = SocketOptions::join_multicast_v4(addr);
if let SocketOptions::Udp(opt) = sock_opt {
assert_eq!(test_value, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_leave_multicast_value_fail() {
let test_value: u32 = 0xc0a80101;
let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
let sock_opt = SocketOptions::leave_multicast_v4(addr);
if let SocketOptions::Udp(opt) = sock_opt {
assert_ne!(test_value, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_udp_send_callback_false_value() {
let sock_opts = SocketOptions::set_udp_send_callback(false);
if let SocketOptions::Udp(opt) = sock_opts {
assert_eq!(0u32, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_udp_send_callback_true_value() {
let sock_opts = SocketOptions::set_udp_send_callback(true);
if let SocketOptions::Udp(opt) = sock_opts {
assert_eq!(1u32, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_udp_recv_timeout_value() {
let test_value = 1500u32;
let sock_opts = SocketOptions::set_udp_receive_timeout(test_value);
if let SocketOptions::Udp(opt) = sock_opts {
assert_eq!(test_value, opt.get_value());
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_get_tcp_recv_timeout_value() {
let test_value = 2500u32;
let sock_opts = SocketOptions::set_tcp_receive_timeout(test_value);
if let SocketOptions::Tcp(opt) = sock_opts {
assert_eq!(test_value, opt.get_value());
} else {
assert!(false);
}
}
#[cfg(feature = "ssl")]
#[test]
fn test_sock_opts_get_sni_array_success() {
let test_value = "hostname".as_bytes();
let sock_opts = SocketOptions::set_sni("hostname").unwrap();
if let SocketOptions::Tcp(opt) = sock_opts {
if let TcpSockOpts::Ssl(ssl) = opt {
assert_eq!(ssl.get_sni_value().unwrap().as_bytes(), test_value);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_sock_opts_udp_join_multicast_u8_value() {
let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
let sock_opts = UdpSockOpts::JoinMulticast(addr);
assert_eq!(u8::from(sock_opts), 0x01u8);
}
#[test]
fn test_sock_opts_udp_leave_multicast_u8_value() {
let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
let sock_opts = UdpSockOpts::LeaveMulticast(addr);
assert_eq!(u8::from(sock_opts), 0x02u8);
}
#[test]
fn test_sock_opts_udp_receive_timeout_u8_value() {
let sock_opts = UdpSockOpts::ReceiveTimeout(1500);
assert_eq!(u8::from(sock_opts), 0xffu8);
}
#[test]
fn test_sock_opts_udp_send_callback_u8_value() {
let sock_opts = UdpSockOpts::SetUdpSendCallback(false);
assert_eq!(u8::from(sock_opts), 0x00u8);
}
#[test]
fn test_sock_opts_tcp_receive_timeout_u8_value() {
let sock_opts = TcpSockOpts::ReceiveTimeout(1500);
assert_eq!(u8::from(sock_opts), 0xffu8);
}
#[cfg(feature = "ssl")]
#[test]
fn test_sock_opts_tcp_ssl_u8_value() {
let host = HostName::from("hostname").unwrap();
let sock_opts = TcpSockOpts::Ssl(SslSockOpts::SetSni(host));
assert_eq!(u8::from(sock_opts), 0xfeu8);
}
#[cfg(feature = "ssl")]
#[test]
fn test_sock_opts_get_tcp_ssl_sni_value() {
let host = HostName::from("hostname").unwrap();
let sock_opts = TcpSockOpts::Ssl(SslSockOpts::SetSni(host));
assert_eq!(sock_opts.get_value(), 0xfeu32);
}
#[cfg(feature = "ssl")]
#[test]
fn test_sock_opts_ssl_sni_u8_value() {
let host = HostName::from("hostname").unwrap();
let sock_opts = SslSockOpts::SetSni(host);
assert_eq!(u8::from(sock_opts), 0x02u8);
}
#[cfg(feature = "ssl")]
#[test]
fn test_sock_opts_ssl_sni_invalid_parameter() {
let test_string =
"This is a test string that definitely contains more than sixty-three bytes of data.";
let sock_opts = SocketOptions::set_sni(test_string);
assert_eq!(sock_opts.err(), Some(StackError::InvalidParameters));
}
#[cfg(feature = "ssl")]
#[test]
fn test_ssl_sock_opt_conv() {
let sock_opt = SslSockOpts::Config(SslSockConfig::EnableSessionCache, true);
let u8_value = u8::from(sock_opt);
assert_eq!(u8_value, u8::from(SslSockConfig::EnableSessionCache));
}
#[cfg(feature = "ssl")]
#[test]
fn test_ssl_sock_opt_ref_conv() {
let sock_opt = SslSockOpts::Config(SslSockConfig::EnableSniValidation, true);
let sock_opt_ref = &sock_opt;
let u8_value = u8::from(sock_opt_ref);
assert_eq!(u8_value, u8::from(SslSockConfig::EnableSniValidation));
}
#[cfg(feature = "ssl")]
#[test]
fn test_ssl_sock_opt_invalid_opt() {
let sock_opt = SslSockOpts::Config(SslSockConfig::EnableSniValidation, true);
let res = sock_opt.get_sni_value();
assert_eq!(res, Err(StackError::InvalidParameters));
}
#[test]
fn test_create_new_mac_address() {
let mac = MacAddress::new(0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6);
assert_eq!(mac.octets(), [0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6]);
let mac = MacAddress::empty();
assert_eq!(mac.octets(), [0u8; MAX_OCTETS_IN_MAC_ADDRESS]);
}
#[test]
fn test_create_mac_address_from_array_success() {
let bytes = [0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6];
let mac = MacAddress::from_bytes(&bytes);
assert!(mac.is_ok());
assert_eq!(mac.unwrap().as_slice(), bytes);
}
#[test]
fn test_create_mac_address_from_array_failure() {
let bytes = [0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0xAA];
let mac = MacAddress::from_bytes(&bytes);
assert_eq!(mac.err(), Some(StackError::InvalidParameters));
}
#[test]
fn test_create_mac_address_mut_array() {
let bytes = [0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6];
let mut mac = MacAddress::from_bytes(&bytes).unwrap();
let mod_mac = mac.as_mut_slice();
for (index, byte) in mod_mac.iter_mut().enumerate() {
*byte = (index * 2) as u8;
}
assert_ne!(mod_mac, &bytes);
}
#[cfg(all(feature = "log", feature = "std"))]
#[test]
fn test_format_mac_address() {
use std::format;
let bytes = [0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6];
let mac = MacAddress::from_bytes(&bytes);
assert_eq!(format!("{}", mac.unwrap()), "A1:B2:C3:D4:E5:F6");
}
}