1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::server::Facade;
use anyhow::{format_err, Error};
use async_trait::async_trait;
use fidl_fuchsia_wlan_common as fidl_common;
use ieee80211::{MacAddr, Ssid, NULL_ADDR};
use serde_json::{from_value, to_value, Value};
use tracing::*;

// Testing helper methods
use crate::wlan::{facade::WlanFacade, types};

use crate::common_utils::common::parse_u64_identifier;

#[async_trait(?Send)]
impl Facade for WlanFacade {
    async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
        match method.as_ref() {
            "scan" => {
                info!(tag = "WlanFacade", "performing wlan scan");
                let results = self.scan().await?;
                info!(tag = "WlanFacade", "received {:?} scan results", results.len());
                to_value(results).map_err(|e| format_err!("error handling scan results: {}", e))
            }
            "scan_for_bss_info" => {
                info!(tag = "WlanFacade", "performing wlan scan");
                let results = self.scan_for_bss_info().await?;
                info!(tag = "WlanFacade", "received {:?} scan results", results.len());
                to_value(results).map_err(|e| format_err!("error handling scan results: {}", e))
            }
            "connect" => {
                let target_ssid = match args.get("target_ssid") {
                    Some(ssid_value) => {
                        let ssid = match ssid_value.as_str() {
                            Some(ssid_value) => Ssid::try_from(ssid_value)?,
                            None => {
                                return Err(format_err!("Please provide a target ssid"));
                            }
                        };
                        ssid
                    }
                    None => return Err(format_err!("Please provide a target ssid")),
                };

                let target_pwd = match args.get("target_pwd") {
                    Some(pwd) => match pwd.clone().as_str() {
                        Some(pwd) => pwd.as_bytes().to_vec(),
                        None => {
                            info!(tag = "WlanFacade", "Please check provided password");
                            vec![0; 0]
                        }
                    },
                    _ => vec![0; 0],
                };

                let target_bss_desc: types::BssDescriptionDef = match args.get("target_bss_desc") {
                    Some(target_bss_desc) => from_value(target_bss_desc.clone())?,
                    None => return Err(format_err!("Please provide a target BSS description")),
                };

                info!(tag = "WlanFacade", "performing wlan connect to SSID: {:?}", target_ssid);
                let results = self.connect(target_ssid, target_pwd, target_bss_desc.into()).await?;
                to_value(results)
                    .map_err(|e| format_err!("error handling connection result: {}", e))
            }
            "get_iface_id_list" => {
                info!(tag = "WlanFacade", "Getting the interface id list.");
                let result = self.get_iface_id_list().await?;
                to_value(result).map_err(|e| format_err!("error handling get_iface_id_list: {}", e))
            }
            "get_phy_id_list" => {
                info!(tag = "WlanFacade", "Getting the phy id list.");
                let result = self.get_phy_id_list().await?;
                to_value(result).map_err(|e| format_err!("error handling get_phy_id_list: {}", e))
            }
            "create_iface" => {
                info!(tag = "WlanFacade", "Performing wlan create_iface");
                let phy_id = match args.get("phy_id") {
                    Some(phy_id) => match phy_id.as_u64() {
                        Some(phy_id) => phy_id as u16,
                        None => return Err(format_err!("Could not parse phy id")),
                    },
                    None => return Err(format_err!("Please provide target phy id")),
                };

                let role = if let Some(role) = args.get("role") {
                    match role.as_str() {
                        Some("Ap") => fidl_common::WlanMacRole::Ap,
                        Some("Client") => fidl_common::WlanMacRole::Client,
                        None => return Err(format_err!("Could not parse role")),
                        other => return Err(format_err!("Invalid iface role: {:?}", other)),
                    }
                } else {
                    return Err(format_err!("Please provide a role for the new iface"));
                };

                let sta_addr: MacAddr = if let Some(mac) = args.get("sta_addr") {
                    match mac.as_str() {
                        Some(mac) => match serde_json::from_str::<[u8; 6]>(mac) {
                            Ok(mac) => mac.into(),
                            Err(e) => {
                                println!(
                                    "Could not parse mac: {:?}, using null addr {}",
                                    e, NULL_ADDR
                                );
                                NULL_ADDR
                            }
                        },
                        None => {
                            println!(
                                "Could not convert sta_addr to string, using null addr {}",
                                NULL_ADDR
                            );
                            NULL_ADDR
                        }
                    }
                } else {
                    println!("No MAC provided in args, using null addr {}", NULL_ADDR);
                    NULL_ADDR
                };

                let result = self.create_iface(phy_id, role, sta_addr).await?;
                to_value(result).map_err(|e| format_err!("error handling create_iface: {}", e))
            }
            "destroy_iface" => {
                info!(tag = "WlanFacade", "Performing wlan destroy_iface");
                let iface_id = parse_u64_identifier(args.clone())?;
                self.destroy_iface(iface_id as u16).await?;
                to_value(true).map_err(|e| format_err!("error handling destroy_iface: {}", e))
            }
            "disconnect" => {
                info!(tag = "WlanFacade", "performing wlan disconnect");
                self.disconnect().await?;
                to_value(true).map_err(|e| format_err!("error handling disconnect: {}", e))
            }
            "query_iface" => {
                let iface_id = match args.get("iface_id") {
                    Some(iface_id) => match iface_id.as_u64() {
                        Some(iface_id) => iface_id as u16,
                        None => return Err(format_err!("Could not parse iface id")),
                    },
                    None => return Err(format_err!("Please provide target iface id")),
                };

                info!(tag = "WlanFacade", "performing wlan query iface");
                let result = self.query_iface(iface_id).await?;
                to_value(result).map_err(|e| format_err!("error handling query iface: {}", e))
            }
            "status" => {
                info!(tag = "WlanFacade", "fetching connection status");
                let result = self.status().await?;
                to_value(result).map_err(|e| format_err!("error handling connection status: {}", e))
            }
            _ => return Err(format_err!("unsupported command!")),
        }
    }
}