wincwifi/manager/
requests.rs

1// Copyright 2023 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::readwrite::{BufferOverflow, Write};
16
17use crate::socket::Socket;
18use core::net::{Ipv4Addr, SocketAddrV4};
19
20use super::constants::{
21    AuthType, WifiChannel, CONNECT_AP_PACKET_SIZE, ENABLE_AP_PACKET_SIZE,
22    SET_SOCK_OPTS_PACKET_SIZE, START_PROVISION_PACKET_SIZE,
23};
24
25use super::net_types::{AccessPoint, Credentials, HostName, Ssid, WepKey, WpaKey};
26
27#[cfg(feature = "ssl")]
28use super::{constants::SET_SSL_SOCK_OPTS_PACKET_SIZE, net_types::SslSockOpts};
29
30#[cfg(feature = "experimental-ecc")]
31use super::{
32    constants::{EccRequestType, SSL_ECC_REQ_PACKET_SIZE},
33    net_types::{EccInfo, EcdhInfo},
34};
35
36#[cfg(feature = "ethernet")]
37use super::constants::NET_XFER_PACKET_SIZE;
38
39/// Prepares the packet to connect to access point.
40///
41/// # Arguments
42///
43/// * `ssid` - The SSID (network name), up to 32 bytes.
44/// * `credentials` - Security credentials (e.g., passphrase or authentication data).
45/// * `channel` - Wi-Fi RF channel.
46/// * `dont_save_credentials` - Whether to save credentials or not.
47///
48/// # Returns
49///
50/// * `[u8; CONNECT_AP_PACKET_SIZE])` - The connect request packet as a fixed-size byte array.
51/// * `BufferOverflow` - If the input data exceeds allowed size or the buffer limit.
52pub fn write_connect_request(
53    ssid: &Ssid,
54    credentials: &Credentials,
55    channel: WifiChannel,
56    dont_save_creds: bool,
57) -> Result<[u8; CONNECT_AP_PACKET_SIZE], BufferOverflow> {
58    let mut result = [0u8; CONNECT_AP_PACKET_SIZE];
59    let mut slice = result.as_mut_slice();
60
61    match credentials {
62        Credentials::Open => {
63            // write padding
64            slice = &mut result[65..];
65            // Write Authentication type (1 byte)
66            slice.write(&[AuthType::Open.into()])?;
67        }
68        Credentials::WpaPSK(key) => {
69            // Write WPA Key (65 Bytes)
70            slice.write(key.as_bytes())?;
71            slice = &mut result[65..];
72            // Write Authentication type (1 byte)
73            slice.write(&[AuthType::WpaPSK.into()])?;
74        }
75        Credentials::S802_1X(user, pass) => {
76            // Write S1x username (21 bytes)
77            slice.write(user.as_bytes())?;
78            slice = &mut result[21..];
79            // Write S1x password (41 bytes)
80            slice.write(pass.as_bytes())?;
81            slice = &mut result[62..];
82            // Padding
83            slice.write(&[0x00u8; 3])?;
84            // Write Authentication type (1 byte)
85            slice.write(&[AuthType::S802_1X.into()])?;
86        }
87        #[cfg(feature = "wep")]
88        Credentials::Wep(key, index) => {
89            // Write Wep Key Index
90            slice.write(&[*index as u8])?;
91            // Write Wep key length
92            slice.write(&[key.len() as u8])?;
93            // Write Wep Key
94            slice.write(key.as_bytes())?;
95            slice = &mut result[32..];
96            // Write padding
97            slice.write(&[0u8; 33])?;
98            // Write Authentication type
99            slice.write(&[AuthType::WEP.into()])?;
100        }
101    };
102    // Padding (2 bytes)
103    slice.write(&[0u8, 0u8])?;
104    // Wifi Channel
105    let ch: u8 = channel.into();
106    slice.write(&(ch as u16).to_le_bytes())?;
107    // SSID
108    slice.write(ssid.as_bytes())?;
109    slice = &mut result[103..];
110    // Write save_credentials
111    slice.write(&[dont_save_creds as u8])?;
112
113    Ok(result)
114}
115
116// tstrM2MScan
117pub fn write_scan_req(channel: u8, scantime: u16) -> Result<[u8; 4], BufferOverflow> {
118    let mut result = [0u8; 4];
119    let mut slice = result.as_mut_slice();
120    slice.write(&channel.to_le_bytes())?;
121    slice.write(&[0u8])?; // reserved
122    slice.write(&scantime.to_le_bytes())?;
123    Ok(result)
124}
125
126// no request struct, just C-string
127pub fn write_gethostbyname_req<'a, const N: usize>(
128    host: &str,
129    buffer: &'a mut [u8; N],
130) -> Result<&'a [u8], BufferOverflow> {
131    let len = host.len();
132    if len + 1 > buffer.len() {
133        return Err(BufferOverflow);
134    }
135    buffer[0..len].copy_from_slice(host.as_bytes());
136    buffer[len] = 0;
137    Ok(&buffer[0..len + 1])
138}
139
140// tstrPingCmd
141pub fn write_ping_req(
142    dest_ip: Ipv4Addr,
143    ttl: u8,
144    count: u16,
145    marker: u8,
146) -> Result<[u8; 12], BufferOverflow> {
147    let mut result = [0x0u8; 12];
148    let mut slice = result.as_mut_slice();
149    let ip: u32 = dest_ip.into();
150    slice.write(&(ip).to_be_bytes())?;
151    slice.write(&[marker, 0xBE, 0xBE, 0xBE])?; // todo
152    slice.write(&count.to_le_bytes())?;
153    slice.write(&[ttl])?;
154    Ok(result)
155}
156
157/// Prepares the packet to bind the given socket to an IPv4 address.
158///
159/// # Arguments
160///
161/// * `socket` – The socket to bind.
162/// * `address` – The IPv4 address to bind the socket to.
163///
164/// # Returns
165///
166/// * `[u8; 12]` – Bind request as fixed size array..
167/// * `BufferOverflow` – If the data exceeds the buffer capacity.
168pub fn write_bind_req(socket: Socket, address: SocketAddrV4) -> Result<[u8; 12], BufferOverflow> {
169    const AF_INET: u16 = 2; // Address family for IPV4.
170
171    let mut result = [0x0u8; 12];
172    let mut slice = result.as_mut_slice();
173    let ip: u32 = (*address.ip()).into();
174
175    slice.write(&AF_INET.to_le_bytes())?;
176    slice.write(&address.port().to_be_bytes())?;
177    slice.write(&ip.to_be_bytes())?;
178    slice.write(&[socket.v, 0])?;
179    slice.write(&socket.s.to_le_bytes())?;
180    Ok(result)
181}
182
183// tstrConnectCmd
184pub fn write_connect_req(
185    socket: Socket,
186    address_family: u16,
187    address: SocketAddrV4,
188    ssl_flags: u8,
189) -> Result<[u8; 12], BufferOverflow> {
190    let mut result = [0x0u8; 12];
191    let mut slice = result.as_mut_slice();
192    let ip: u32 = (*address.ip()).into();
193    slice.write(&address_family.to_le_bytes())?;
194    slice.write(&address.port().to_be_bytes())?;
195    slice.write(&ip.to_be_bytes())?;
196    slice.write(&[socket.v, ssl_flags])?;
197    slice.write(&socket.s.to_le_bytes())?;
198    Ok(result)
199}
200
201// tstrSendCmd
202pub fn write_sendto_req(
203    socket: Socket,
204    address_family: u16,
205    address: SocketAddrV4,
206    len: usize,
207) -> Result<[u8; 16], BufferOverflow> {
208    let mut result = [0x0u8; 16];
209    let mut slice = result.as_mut_slice();
210    let ip: u32 = (*address.ip()).into();
211    slice.write(&[socket.v, 0])?;
212    slice.write(&(len as u16).to_le_bytes())?;
213    slice.write(&address_family.to_le_bytes())?;
214    slice.write(&address.port().to_be_bytes())?;
215    slice.write(&ip.to_be_bytes())?;
216    slice.write(&socket.s.to_le_bytes())?;
217    slice.write(&[0, 0])?;
218    Ok(result)
219}
220
221// tstrListenCmd
222pub fn write_listen_req(socket: Socket, backlog: u8) -> Result<[u8; 4], BufferOverflow> {
223    let mut result = [0x0u8; 4];
224    let mut slice = result.as_mut_slice();
225    slice.write(&[socket.v, backlog])?;
226    slice.write(&socket.s.to_le_bytes())?;
227    Ok(result)
228}
229
230//tstrRecvCmd
231pub fn write_recv_req(socket: Socket, timeout: u32) -> Result<[u8; 8], BufferOverflow> {
232    let mut result = [0x0u8; 8];
233    let mut slice = result.as_mut_slice();
234    slice.write(&timeout.to_le_bytes())?;
235    slice.write(&[socket.v, 0])?;
236    slice.write(&socket.s.to_le_bytes())?;
237    Ok(result)
238}
239
240// tstrCloseCmd
241pub fn write_close_req(socket: Socket) -> Result<[u8; 4], BufferOverflow> {
242    let mut result = [0x0u8; 4];
243    let mut slice = result.as_mut_slice();
244    slice.write(&[socket.v, 0])?;
245    slice.write(&socket.s.to_le_bytes())?;
246    Ok(result)
247}
248
249/// Prepares the packet to set socket options.
250///
251/// # Arguments
252///
253/// * `socket` - The identifier for the socket to configure.
254/// * `option` - Socket option to set.
255/// * `value` - The value to assign to the specified socket option.
256///
257/// # Returns
258///
259/// * `[u8; SET_SOCK_OPTS_PACKET_SIZE]` – Set socket option request packet as fixed-array.
260/// * `BufferOverflow` – If the buffer overflows while preparing the packet.
261pub fn write_setsockopt_req(
262    socket: Socket,
263    option: u8,
264    value: u32,
265) -> Result<[u8; SET_SOCK_OPTS_PACKET_SIZE], BufferOverflow> {
266    let mut result = [0x0u8; SET_SOCK_OPTS_PACKET_SIZE];
267    let mut slice = result.as_mut_slice();
268    // Socket Option Value (4 bytes)
269    slice.write(&value.to_le_bytes())?;
270    // Socket Identifier (1 byte) and Socket Option (1 byte)
271    slice.write(&[socket.v, option])?;
272    // Session ID (2 byte)
273    slice.write(&socket.s.to_le_bytes())?;
274    Ok(result)
275}
276
277/// Prepares the packet to set SSL socket options.
278///
279/// # Arguments
280///
281/// * `socket` - The identifier for the socket to configure.
282/// * `option` - SSL socket option to set.
283///
284/// # Returns
285///
286/// * `[u8; SET_SSL_SOCK_OPTS_PACKET_SIZE]` – Set SSL socket option request packet as fixed-array.
287/// * `BufferOverflow` – If the buffer overflows while preparing the packet.
288#[cfg(feature = "ssl")]
289pub fn write_ssl_setsockopt_req(
290    socket: Socket,
291    option: &SslSockOpts,
292) -> Result<[u8; SET_SSL_SOCK_OPTS_PACKET_SIZE], BufferOverflow> {
293    let mut result = [0x0u8; SET_SSL_SOCK_OPTS_PACKET_SIZE];
294    let mut slice = result.as_mut_slice();
295
296    // Get value
297    let value = option.get_sni_value().map_err(|_| BufferOverflow)?;
298
299    // Socket Identifier (1 byte) and Socket Option (1 byte)
300    slice.write(&[socket.v, u8::from(option)])?;
301    // Session ID (2 byte)
302    slice.write(&socket.s.to_le_bytes())?;
303    // Option length
304    slice.write(&(value.len() as u32).to_le_bytes())?;
305    // Option Value
306    slice.write(value.as_bytes())?;
307
308    Ok(result)
309}
310
311/// Prepares the packet for a PRNG request.
312///
313/// Packet Structure:
314///
315/// | Input Buffer Address | Number of Random Bytes to Generate | Padding |
316/// |----------------------|------------------------------------|---------|
317/// | 4 Bytes              | 2 Bytes                            | 2 Bytes |
318///
319/// # Arguments
320///
321/// * `addr` - The address of the input buffer for storing PRNG data.
322/// * `len` - The length of the input buffer, or the number of random bytes to generate.
323///
324/// # Returns
325///
326/// * `[u8]` - An array of 8 bytes representing the request packet for PRNG.
327/// * `BufferOverflow` - If the data exceeds the buffer limit during packet preparation.
328pub fn write_prng_req(addr: u32, len: u16) -> Result<[u8; 8], BufferOverflow> {
329    let mut req = [0x00u8; 8];
330    let mut slice = req.as_mut_slice();
331    slice.write(&addr.to_le_bytes())?;
332    slice.write(&len.to_le_bytes())?;
333    Ok(req)
334}
335
336/// Prepares the packet to start the provisioning mode.
337///
338/// Packet Structure:
339///
340/// |       Name        | Bytes |      Name        | Bytes |
341/// |-------------------|-------|------------------|-------|
342/// |       SSID        |   33  |     Channel      |   1   |
343/// |     Key Size      |   1   |     Wep key      |   1   |
344/// |     Wep key       |   27  |     Security     |   1   |
345/// |  SSID Visibility  |   1   |  DHCP server IP  |   4   |
346/// |      WPA Key      |   65  |     Padding      |   2   |
347/// |      DNS url      |   64  |   Http Redirect  |   1   |
348/// |      Padding      |   3   |                  |       |
349///
350///
351/// # Arguments
352///
353/// * `ap` - An `AccessPoint` struct containing the SSID, passphrase, and other network details.
354/// * `dns` - DNS redirect URL as a string slice (max 63 bytes).
355/// * `http_redirect` - Whether HTTP redirect is enabled.
356///
357/// # Returns
358///
359/// * `[u8; START_PROVISION_PACKET_SIZE])` - The provisioning request packet as a fixed-size byte array.
360/// * `BufferOverflow` - If the input data exceeds allowed size or the buffer limit.
361pub fn write_start_provisioning_req(
362    ap: &AccessPoint,
363    hostname: &HostName,
364    http_redirect: bool,
365) -> Result<[u8; START_PROVISION_PACKET_SIZE], BufferOverflow> {
366    let mut req = [0u8; START_PROVISION_PACKET_SIZE];
367    let mut slice = req.as_mut_slice();
368
369    // Set parameters for WEP
370    let wep_key_index: u8;
371    let wep_key: WepKey;
372    #[cfg(feature = "wep")]
373    {
374        if let Credentials::Wep(key, index) = ap.key {
375            wep_key_index = index.into();
376            wep_key = key;
377        } else {
378            wep_key_index = 0;
379            wep_key = WepKey::new();
380        }
381    }
382
383    #[cfg(not(feature = "wep"))]
384    {
385        wep_key_index = 0;
386        wep_key = WepKey::new();
387    }
388
389    // Set parameters for WPA-PSK
390    let wpa_key = if let Credentials::WpaPSK(key) = ap.key {
391        key
392    } else {
393        WpaKey::new()
394    };
395
396    // dhcp
397    let dhcp: u32 = ap.ip.into();
398
399    // SSID
400    slice.write(ap.ssid.as_bytes())?;
401    // Null termination
402    slice = &mut req[32..];
403    slice.write(&[0u8])?;
404    // WiFi channel
405    slice.write(&[(ap.channel).into()])?;
406    // Wep key Index
407    slice.write(&[wep_key_index])?;
408    // Wep/WPA key size
409    slice.write(&[ap.key.key_len() as u8])?;
410    // Wep key
411    slice.write(wep_key.as_bytes())?;
412    // Null termination
413    slice = &mut req[62..];
414    slice.write(&[0u8])?;
415    // Security type
416    slice.write(&[(ap.key).into()])?;
417    // SSID visibility
418    slice.write(&[ap.ssid_hidden as u8])?;
419    // dhcp server
420    slice.write(&dhcp.to_be_bytes())?;
421    // WPA key
422    slice.write(wpa_key.as_bytes())?;
423    // WINC firmware supports 64 bytes (+1 over standard) plus null terminator.
424    slice = &mut req[132..];
425    // Null termination
426    slice.write(&[0u8, 0u8])?;
427    // Padding
428    slice.write(&[0u8, 0u8])?;
429    // Device Domain name
430    slice.write(hostname.as_bytes())?;
431    // Null termination
432    slice = &mut req[199..];
433    slice.write(&[0u8])?;
434    // Http redirect
435    slice.write(&[http_redirect as u8])?;
436    // Padding
437    slice.write(&[0u8, 0u8, 0u8])?;
438
439    Ok(req)
440}
441
442/// Prepares the packet to enable the access point mode.
443///
444/// # Arguments
445///
446/// * `ap` - An `AccessPoint` struct containing the SSID, passphrase, and other network details.
447///
448/// # Returns
449///
450/// * `[u8; ENABLE_AP_PACKET_SIZE])` - The access point mode request packet as a fixed-size byte array.
451/// * `BufferOverflow` - If the input data exceeds allowed size or the buffer limit.
452pub fn write_en_ap_req(ap: &AccessPoint) -> Result<[u8; ENABLE_AP_PACKET_SIZE], BufferOverflow> {
453    let mut req = [0u8; ENABLE_AP_PACKET_SIZE];
454    let mut slice = req.as_mut_slice();
455
456    // Set parameters for WEP
457    let wep_key_index: u8;
458    let wep_key: WepKey;
459    #[cfg(feature = "wep")]
460    {
461        if let Credentials::Wep(key, index) = ap.key {
462            wep_key_index = index.into();
463            wep_key = key;
464        } else {
465            wep_key_index = 0;
466            wep_key = WepKey::new();
467        }
468    }
469
470    #[cfg(not(feature = "wep"))]
471    {
472        wep_key_index = 0;
473        wep_key = WepKey::new();
474    }
475
476    // Set parameters for WPA-PSK
477    let wpa_key = if let Credentials::WpaPSK(key) = ap.key {
478        key
479    } else {
480        WpaKey::new()
481    };
482
483    // dhcp
484    let dhcp: u32 = ap.ip.into();
485
486    // SSID (33 bytes)
487    slice.write(ap.ssid.as_bytes())?;
488    slice = &mut req[33..];
489    // WiFi channel (1 byte)
490    slice.write(&[(ap.channel).into()])?;
491    // Wep key Index (1 byte)
492    slice.write(&[wep_key_index])?;
493    // Wep/WPA key size (1 byte)
494    slice.write(&[ap.key.key_len() as u8])?;
495    // Wep key (27 bytes)
496    slice.write(wep_key.as_bytes())?;
497    slice = &mut req[63..];
498    // Security type (1 byte)
499    slice.write(&[(ap.key).into()])?;
500    // SSID visibility (1 byte)
501    slice.write(&[ap.ssid_hidden as u8])?;
502    // dhcp server (4 byte)
503    slice.write(&dhcp.to_be_bytes())?;
504    // WPA key (65 byte)
505    slice.write(wpa_key.as_bytes())?;
506
507    Ok(req)
508}
509
510/// Prepares a packet for writing an SSL ECC response.
511///
512/// # Arguments
513///
514/// * `ecc_info` - Reference to the ECC response information.
515/// * `ecdh_info` - An optional reference to the ECDH response information.
516///
517/// # Returns
518///
519/// * `Ok([u8; SSL_ECC_REQ_PACKET_SIZE])` – A fixed-size byte array containing the ECC response packet.
520/// * `Err(BufferOverflow)` – If the input data exceeds the allowed size or buffer limit.
521#[cfg(feature = "experimental-ecc")]
522pub(crate) fn write_ssl_ecc_resp(
523    ecc_info: &EccInfo,
524    ecdh_info: Option<&EcdhInfo>,
525) -> Result<[u8; SSL_ECC_REQ_PACKET_SIZE], BufferOverflow> {
526    let mut req = [0u8; SSL_ECC_REQ_PACKET_SIZE];
527    let mut slice = req.as_mut_slice();
528
529    // ECC request type (2 bytes)
530    let ecc_req_type: u16 = ecc_info.req.into();
531    slice.write(&ecc_req_type.to_le_bytes())?;
532    // Status (2 bytes)
533    slice.write(&ecc_info.status.to_le_bytes())?;
534    // User data (4 bytes)
535    slice.write(&ecc_info.user_data.to_le_bytes())?;
536    // Sequence Number (4 bytes)
537    slice.write(&ecc_info.seq_num.to_le_bytes())?;
538
539    if ecc_info.req == EccRequestType::ClientEcdh || ecc_info.req == EccRequestType::GenerateKey {
540        if let Some(ecdh_info) = ecdh_info.as_ref() {
541            // X-coordinates of ECC points (32 bytes)
542            slice.write(&ecdh_info.ecc_point.x_pos)?;
543            // Y-coordinates of ECC points (32 bytes)
544            slice.write(&ecdh_info.ecc_point.y_pos)?;
545            // Point Size (2 bytes)
546            slice.write(&ecdh_info.ecc_point.point_size.to_le_bytes())?;
547            // Private Key ID (2 bytes)
548            slice.write(&ecdh_info.ecc_point.private_key_id.to_le_bytes())?;
549        }
550    }
551
552    if ecc_info.req == EccRequestType::ClientEcdh || ecc_info.req == EccRequestType::ServerEcdh {
553        if let Some(ecdh_info) = ecdh_info.as_ref() {
554            // Private Key (32 bytes)
555            slice.write(&ecdh_info.private_key)?;
556        }
557    }
558
559    Ok(req)
560}
561
562/// Prepares a request packet for sending a network information.
563///
564/// # Arguments
565///
566/// * `net_pkt_len` - The length of the network packet payload, in bytes.
567/// * `net_header_len` - The length of the network packet header, in bytes.
568///
569/// # Returns
570///
571/// * `Ok([u8; NET_XFER_PACKET_SIZE])` - A fixed-size array containing the network
572///   packet request.
573/// * `Err(BufferOverflow)` - If the packet data exceeds the available buffer size.
574#[cfg(feature = "ethernet")]
575pub(crate) fn write_send_net_pkt_req(
576    net_pkt_len: u16,
577    net_header_len: u16,
578) -> Result<[u8; NET_XFER_PACKET_SIZE], BufferOverflow> {
579    let mut req = [0u8; NET_XFER_PACKET_SIZE];
580    let mut slice = req.as_mut_slice();
581
582    slice.write(&net_pkt_len.to_le_bytes())?;
583    slice.write(&net_header_len.to_le_bytes())?;
584
585    Ok(req)
586}
587
588#[cfg(test)]
589mod tests {
590    use core::str::FromStr;
591
592    use crate::{S8Password, S8Username, SocketOptions, Ssid};
593
594    #[cfg(feature = "wep")]
595    use crate::{WepKey, WepKeyIndex};
596
597    use super::*;
598    #[test]
599    fn test_scan() {
600        assert_eq!(write_scan_req(1, 12).unwrap(), [1, 0, 12, 0]);
601        assert_eq!(write_scan_req(255, 258).unwrap(), [255, 0, 2, 1]);
602    }
603    #[test]
604    fn test_ping() {
605        assert_eq!(
606            write_ping_req(Ipv4Addr::new(1, 2, 3, 4), 5, 258, 0xDE).unwrap(),
607            [1, 2, 3, 4, 0xDE, 0xBE, 0xBE, 0xBE, 2, 1, 5, 0]
608        );
609        assert_eq!(
610            write_ping_req(Ipv4Addr::new(255, 2, 3, 4), 4, 258, 0xBA).unwrap(),
611            [0xFF, 2, 3, 4, 0xBA, 0xBE, 0xBE, 0xBE, 2, 1, 4, 0]
612        );
613    }
614
615    #[test]
616    fn test_dns() {
617        let mut buff = [0u8; 6];
618        assert_eq!(
619            write_gethostbyname_req("abc", &mut buff).unwrap(),
620            [97, 98, 99, 0]
621        );
622        assert_eq!(
623            write_gethostbyname_req("abcde", &mut buff).unwrap(),
624            [97, 98, 99, 100, 101, 0]
625        );
626        assert!(matches!(
627            write_gethostbyname_req("abcdef", &mut buff),
628            Err(BufferOverflow)
629        ));
630    }
631    #[test]
632    fn test_bind() {
633        assert_eq!(
634            write_bind_req(
635                Socket::new(7, 521),
636                SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 32769)
637            )
638            .unwrap(),
639            [
640                2, 0, // af
641                128, 1, 1, 2, 3, 4, 7, 0, 9, 2
642            ]
643        );
644        assert_eq!(
645            write_bind_req(
646                Socket::new(0, 3),
647                SocketAddrV4::new(Ipv4Addr::new(255, 2, 3, 4), 1000)
648            )
649            .unwrap(),
650            [2, 0, 3, 232, 0xFF, 2, 3, 4, 0, 0, 3, 0]
651        )
652    }
653    #[test]
654    fn test_connect() {
655        assert_eq!(
656            write_connect_req(
657                Socket::new(7, 1030),
658                2,
659                SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 0xFABA),
660                42
661            )
662            .unwrap(),
663            [
664                2, 0, // address family
665                0xFA, 0xBA, // port
666                1, 2, 3, 4, //ip
667                7, 42, 6, 4
668            ]
669        );
670        assert_eq!(
671            write_connect_req(
672                Socket::new(0, 1),
673                2,
674                SocketAddrV4::new(Ipv4Addr::new(192, 168, 5, 196), 20002),
675                0
676            )
677            .unwrap(),
678            [
679                2, 0, // addr
680                0x4E, 0x22, // port
681                0xC0, 0xA8, 0x5, 0xC4, // ipaddr
682                0x00, // sock
683                0,    // sslflags
684                0x1, 00 // session
685            ]
686        );
687    }
688    #[test]
689    fn test_sendto() {
690        assert_eq!(
691            write_sendto_req(
692                Socket::new(7, 521),
693                2,
694                SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 0xFABA),
695                10
696            )
697            .unwrap(),
698            [7, 0, 10, 0, 2, 0, 0xFA, 0xBA, 1, 2, 3, 4, 9, 2, 0, 0,]
699        );
700        assert_eq!(
701            write_sendto_req(
702                Socket::new(7, 521),
703                2,
704                SocketAddrV4::new(Ipv4Addr::new(192, 168, 5, 196), 0x214E),
705                10
706            )
707            .unwrap(),
708            [7, 0, 10, 0, 2, 0, 0x21, 0x4E, 192, 168, 5, 196, 9, 2, 0, 0,]
709        )
710    }
711
712    #[test]
713    fn test_listen() {
714        assert_eq!(
715            write_listen_req(Socket::new(1, 258), 2).unwrap(),
716            [1, 2, 2, 1]
717        );
718    }
719    #[test]
720    fn test_recv() {
721        assert_eq!(
722            write_recv_req(Socket::new(1, 258), 0xDEADBEEF).unwrap(),
723            [0xEF, 0xBE, 0xAD, 0xDE, 1, 0, 2, 1]
724        )
725    }
726
727    #[test]
728    fn test_close() {
729        assert_eq!(write_close_req(Socket::new(1, 258)).unwrap(), [1, 0, 2, 1]);
730    }
731    #[test]
732    fn test_setsockopt() {
733        assert_eq!(
734            write_setsockopt_req(Socket::new(1, 258), 42, 0xDEADBEEF).unwrap(),
735            [0xEF, 0xBE, 0xAD, 0xDE, 1, 42, 2, 1]
736        );
737    }
738
739    #[test]
740    fn test_wpa_connect() {
741        let test_vector = [
742            0x73u8, 0x75, 0x70, 0x65, 0x72, 0x5F, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5F, 0x70,
743            0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
744            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
745            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
746            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00,
747            0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x00, 0x00, 0x00,
748            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
750        ];
751        let test_ssid = Ssid::from("sample_ssid").unwrap();
752        let test_pass = Credentials::WpaPSK(WpaKey::from("super_secret_password").unwrap());
753        assert_eq!(
754            test_vector,
755            write_connect_request(&test_ssid, &test_pass, WifiChannel::Channel9, true).unwrap()
756        );
757    }
758
759    #[test]
760    fn test_open_connect() {
761        let test_vector = [
762            0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
763            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00,
767            0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x00, 0x00, 0x00,
768            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770        ];
771        let test_ssid = Ssid::from("sample_ssid").unwrap();
772        let test_pass = Credentials::Open;
773        assert_eq!(
774            test_vector,
775            write_connect_request(&test_ssid, &test_pass, WifiChannel::Channel2, false).unwrap()
776        );
777    }
778
779    #[test]
780    fn test_s802x_connect() {
781        let test_vector = [
782            0x75u8, 0x73, 0x65, 0x72, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72,
784            0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
785            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
786            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xFF, 0x00,
787            0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x00, 0x00, 0x00,
788            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790        ];
791        let test_ssid = Ssid::from("sample_ssid").unwrap();
792        let test_username = S8Username::from("username").unwrap();
793        let test_password = S8Password::from("password").unwrap();
794        let test_pass = Credentials::S802_1X(test_username, test_password);
795        assert_eq!(
796            test_vector,
797            write_connect_request(&test_ssid, &test_pass, WifiChannel::ChannelAll, false).unwrap()
798        );
799    }
800
801    #[cfg(feature = "wep")]
802    #[test]
803    fn test_wep_connect() {
804        let test_vector = [
805            0x1u8, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00,
806            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807            0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00,
810            0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x00, 0x00, 0x00,
811            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813        ];
814        let test_ssid = Ssid::from("sample_ssid").unwrap();
815        let test_password = WepKey::from("password").unwrap();
816        let test_pass = Credentials::Wep(test_password, WepKeyIndex::Key1);
817        assert_eq!(
818            test_vector,
819            write_connect_request(&test_ssid, &test_pass, WifiChannel::Channel9, false).unwrap()
820        );
821    }
822
823    #[test]
824    fn test_prng_request() {
825        let request = [0xDC, 0x65, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00];
826        let addr = 0x200065DC;
827        let len = 32;
828        assert_eq!(write_prng_req(addr, len).unwrap(), request);
829    }
830
831    #[test]
832    fn test_start_provisioning_request() {
833        let valid_req: [u8; START_PROVISION_PACKET_SIZE] = [
834            /* Ssid */ 116, 101, 115, 116, 95, 115, 115, 105, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0,
835            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Wifi Channel */ 1,
836            /* Wep key Index */ 0, /* Wep/Wpa Key Size */ 13, /* Wep key */ 0, 0, 0,
837            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
838            /* Security Type */ 2, /* ssid hidden */ 0, /* DHCP Server */ 0xC0,
839            0xA8, 0x01, 0x01, /* WPA Key */ 116, 101, 115, 116, 95, 112, 97, 115, 115, 119,
840            111, 114, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
841            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
842            /* padding */ 0, 0, /* hostname */ 97, 100, 109, 105, 110, 0, 0, 0, 0, 0, 0,
843            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
844            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
845            /* Http redirect */ 0, /* padding */ 0, 0, 0,
846        ];
847        let ap_ssid = Ssid::from("test_ssid").unwrap();
848        let psk = WpaKey::from("test_password").unwrap();
849        let access_point = AccessPoint::wpa(&ap_ssid, &psk);
850        let hostname = HostName::from("admin").unwrap();
851
852        let result = write_start_provisioning_req(&access_point, &hostname, false).unwrap();
853
854        assert_eq!(result, valid_req);
855    }
856
857    #[test]
858    fn test_write_en_ap_req() {
859        let valid_req: [u8; ENABLE_AP_PACKET_SIZE] = [
860            /* Ssid */ 116, 101, 115, 116, 95, 115, 115, 105, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0,
861            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Wifi Channel */ 1,
862            /* Wep key Index */ 0, /* Wep/Wpa Key Size */ 13, /* Wep key */ 0, 0, 0,
863            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
864            /* Security Type */ 2, /* ssid hidden */ 0, /* DHCP Server */ 0xC0,
865            0xA8, 0x01, 0x01, /* WPA Key */ 116, 101, 115, 116, 95, 112, 97, 115, 115, 119,
866            111, 114, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
867            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
868            /* padding */ 0, 0,
869        ];
870        let ap_ssid = Ssid::from("test_ssid").unwrap();
871        let psk = WpaKey::from("test_password").unwrap();
872        let access_point = AccessPoint::wpa(&ap_ssid, &psk);
873
874        let result = write_en_ap_req(&access_point);
875
876        assert_eq!(result.ok(), Some(valid_req))
877    }
878
879    #[cfg(feature = "ssl")]
880    #[test]
881    fn test_write_ssl_setsockopt_req() {
882        let valid_req: [u8; SET_SSL_SOCK_OPTS_PACKET_SIZE] = [
883            /* Socket Identifier */ 0x01, /* Socket Option */ 0x02,
884            /* Session Id */ 0x16, 0x00, /* Option length */ 0x08, 0x00, 0x00, 0x00,
885            /* Option Value */ 0x68, 0x6F, 0x73, 0x74, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x00,
886            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
887            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
888            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
889            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
890        ];
891        let host = HostName::from("hostname").unwrap();
892        let ssl_opt = SslSockOpts::SetSni(host);
893        let test_req = write_ssl_setsockopt_req(Socket::new(1, 22), &ssl_opt);
894
895        assert!(test_req.is_ok());
896
897        assert_eq!(test_req.unwrap(), valid_req);
898    }
899
900    #[test]
901    fn test_write_setsockopt_req() {
902        let valid_req: [u8; SET_SOCK_OPTS_PACKET_SIZE] = [
903            /* Option Value */ 0x0c0, 0xa8, 0x01, 0x01, /* Socket Identifier */ 0x02,
904            /* Socket Option */ 0x01, /* Session Id */ 0x02, 0x00,
905        ];
906        let addr = Ipv4Addr::from_str("192.168.1.1").unwrap();
907        let sock_opts = SocketOptions::join_multicast_v4(addr);
908        if let SocketOptions::Udp(opts) = sock_opts {
909            let test_req = write_setsockopt_req(Socket::new(2, 2), opts.into(), opts.get_value());
910
911            assert!(test_req.is_ok());
912
913            assert_eq!(test_req.unwrap(), valid_req);
914        } else {
915            assert!(false);
916        }
917    }
918}