• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021, The Android Open Source Project
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 
15 //! This connects to "rootcanal" and provides a simulated
16 //! Nfc chip as well as a simulated environment.
17 
18 use bytes::{BufMut, BytesMut};
19 use log::{debug, Level};
20 use logger::{self, Config};
21 use nfc_packets::nci;
22 use nfc_packets::nci::{CommandChild, NciChild};
23 use nfc_packets::nci::{
24     ConfigParams, ConfigStatus, GetConfigResponseBuilder, NciVersion, ParamIds,
25     ResetNotificationBuilder, ResetResponseBuilder, ResetTrigger, ResetType,
26     SetConfigResponseBuilder,
27 };
28 use nfc_packets::nci::{InitResponseBuilder, NfccFeatures, RfInterface};
29 use nfc_packets::nci::{NciMsgType, NciPacket, Packet, PacketBoundaryFlag};
30 use std::collections::HashMap;
31 use std::convert::TryInto;
32 use std::mem::size_of_val;
33 use std::sync::Arc;
34 use thiserror::Error;
35 use tokio::io;
36 use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader, ErrorKind};
37 use tokio::net::TcpListener;
38 use tokio::sync::RwLock;
39 
40 /// Result type
41 type Result<T> = std::result::Result<T, RootcanalError>;
42 
43 #[derive(Debug, Error)]
44 enum RootcanalError {
45     #[error("Termination request")]
46     TerminateTask,
47     #[error("Socket error")]
48     IoError(#[from] io::Error),
49     #[error("Unsupported command packet")]
50     UnsupportedCommand,
51     #[error("Packet did not parse correctly")]
52     InvalidPacket,
53     #[error("Packet type not supported")]
54     UnsupportedPacket,
55 }
56 
57 /// Provides storage for internal configuration parameters
58 #[derive(Clone)]
59 pub struct InternalConfiguration {
60     map: Arc<RwLock<HashMap<ParamIds, Vec<u8>>>>,
61 }
62 
63 impl InternalConfiguration {
64     /// InternalConfiguration constructor
new() -> Self65     pub async fn new() -> Self {
66         let ic = InternalConfiguration { map: Arc::new(RwLock::new(HashMap::new())) };
67         let mut map = ic.map.write().await;
68         map.insert(ParamIds::LfT3tMax, vec![0x10u8]);
69         drop(map);
70         ic
71     }
72 
73     /// Set a configuration parameter
set(&mut self, parameter: ParamIds, value: Vec<u8>)74     pub async fn set(&mut self, parameter: ParamIds, value: Vec<u8>) {
75         self.map.write().await.insert(parameter, value);
76     }
77 
78     /// Gets a parameter value or None
get(&mut self, parameter: ParamIds) -> Option<Vec<u8>>79     pub async fn get(&mut self, parameter: ParamIds) -> Option<Vec<u8>> {
80         self.map.read().await.get(&parameter).map(|v| (*v).clone())
81     }
82 
83     /// Clears the allocated storage
clear(&mut self)84     pub async fn clear(&mut self) {
85         self.map.write().await.clear();
86     }
87 }
88 
89 const TERMINATION: u8 = 4u8;
90 
91 #[tokio::main]
main() -> io::Result<()>92 async fn main() -> io::Result<()> {
93     logger::init(Config::default().with_tag_on_device("nfc-rc").with_min_level(Level::Trace));
94 
95     let listener = TcpListener::bind("127.0.0.1:54323").await?;
96 
97     for _ in 0..2 {
98         let (mut sock, _) = listener.accept().await?;
99 
100         tokio::spawn(async move {
101             let (rd, mut wr) = sock.split();
102             let mut rd = BufReader::new(rd);
103             let config = InternalConfiguration::new().await;
104             loop {
105                 if let Err(e) = process(config.clone(), &mut rd, &mut wr).await {
106                     match e {
107                         RootcanalError::TerminateTask => break,
108                         RootcanalError::IoError(e) => {
109                             if e.kind() == ErrorKind::UnexpectedEof {
110                                 break;
111                             }
112                         }
113                         _ => panic!("Communication error: {:?}", e),
114                     }
115                 }
116             }
117         })
118         .await?;
119     }
120     Ok(())
121 }
122 
process<R, W>(config: InternalConfiguration, reader: &mut R, writer: &mut W) -> Result<()> where R: AsyncReadExt + Unpin, W: AsyncWriteExt + Unpin,123 async fn process<R, W>(config: InternalConfiguration, reader: &mut R, writer: &mut W) -> Result<()>
124 where
125     R: AsyncReadExt + Unpin,
126     W: AsyncWriteExt + Unpin,
127 {
128     let mut buffer = BytesMut::with_capacity(1024);
129     let len: usize = reader.read_u16().await?.into();
130     buffer.resize(len, 0);
131     reader.read_exact(&mut buffer).await?;
132     let frozen = buffer.freeze();
133     debug!("{:?}", &frozen);
134     let pkt_type = (frozen[0] >> 5) & 0x7;
135     debug!("packet {} received len={}", &pkt_type, &len);
136     if pkt_type == NciMsgType::Command as u8 {
137         match NciPacket::parse(&frozen) {
138             Ok(p) => command_response(config, writer, p).await,
139             Err(_) => Err(RootcanalError::InvalidPacket),
140         }
141     } else if pkt_type == TERMINATION {
142         Err(RootcanalError::TerminateTask)
143     } else {
144         Err(RootcanalError::UnsupportedPacket)
145     }
146 }
147 
148 const MAX_PAYLOAD: u8 = 255;
149 
command_response<W>( mut config: InternalConfiguration, out: &mut W, cmd: NciPacket, ) -> Result<()> where W: AsyncWriteExt + Unpin,150 async fn command_response<W>(
151     mut config: InternalConfiguration,
152     out: &mut W,
153     cmd: NciPacket,
154 ) -> Result<()>
155 where
156     W: AsyncWriteExt + Unpin,
157 {
158     let pbf = PacketBoundaryFlag::CompleteOrFinal;
159     let gid = 0u8;
160     let mut status = nci::Status::Ok;
161     match cmd.specialize() {
162         NciChild::Command(cmd) => match cmd.specialize() {
163             CommandChild::ResetCommand(rst) => {
164                 write_nci(out, (ResetResponseBuilder { gid, pbf, status }).build()).await?;
165                 write_nci(
166                     out,
167                     (ResetNotificationBuilder {
168                         gid,
169                         pbf,
170                         trigger: ResetTrigger::ResetCommand,
171                         config_status: if rst.get_reset_type() == ResetType::KeepConfig {
172                             ConfigStatus::ConfigKept
173                         } else {
174                             ConfigStatus::ConfigReset
175                         },
176                         nci_version: NciVersion::Version20,
177                         manufacturer_id: 0,
178                         mfsi: Vec::new(),
179                     })
180                     .build(),
181                 )
182                 .await
183             }
184             CommandChild::InitCommand(_) => {
185                 let nfcc_feat = [0u8; 5];
186                 let rf_int = [0u8; 2];
187                 write_nci(
188                     out,
189                     (InitResponseBuilder {
190                         gid,
191                         pbf,
192                         status,
193                         nfcc_features: NfccFeatures::parse(&nfcc_feat).unwrap(),
194                         max_log_conns: 0,
195                         max_rout_tbls_size: 0x0000,
196                         max_ctrl_payload: MAX_PAYLOAD,
197                         max_data_payload: MAX_PAYLOAD,
198                         num_of_credits: 0,
199                         max_nfcv_rf_frame_sz: 64,
200                         rf_interface: vec![RfInterface::parse(&rf_int).unwrap(); 1],
201                     })
202                     .build(),
203                 )
204                 .await
205             }
206             CommandChild::SetConfigCommand(sc) => {
207                 for cp in sc.get_params() {
208                     if cp.valm.len() > 251 {
209                         status = nci::Status::InvalidParam;
210                         break;
211                     }
212                     config.set(cp.paramid, cp.valm.clone()).await;
213                 }
214                 write_nci(
215                     out,
216                     (SetConfigResponseBuilder { gid, pbf, status, paramids: Vec::new() }).build(),
217                 )
218                 .await
219             }
220             CommandChild::GetConfigCommand(gc) => {
221                 let mut cpv: Vec<ConfigParams> = Vec::new();
222                 for paramid in gc.get_paramids() {
223                     let mut cp = ConfigParams { paramid: paramid.pids, valm: Vec::new() };
224                     if status == nci::Status::Ok {
225                         if let Some(val) = config.get(paramid.pids).await {
226                             cp.valm = val;
227                         } else {
228                             status = nci::Status::InvalidParam;
229                             cpv.clear();
230                         }
231                     } else if config.get(paramid.pids).await.is_some() {
232                         continue;
233                     }
234                     cpv.push(cp);
235                     // The Status field takes a byte
236                     if size_of_val(&*cpv) > (MAX_PAYLOAD - 1).into() {
237                         cpv.pop();
238                         if status == nci::Status::Ok {
239                             status = nci::Status::MessageSizeExceeded;
240                         }
241                         break;
242                     }
243                 }
244                 write_nci(out, (GetConfigResponseBuilder { gid, pbf, status, params: cpv }).build())
245                     .await
246             }
247             _ => Err(RootcanalError::UnsupportedCommand),
248         },
249         _ => Err(RootcanalError::InvalidPacket),
250     }
251 }
252 
write_nci<W, T>(writer: &mut W, rsp: T) -> Result<()> where W: AsyncWriteExt + Unpin, T: Into<NciPacket>,253 async fn write_nci<W, T>(writer: &mut W, rsp: T) -> Result<()>
254 where
255     W: AsyncWriteExt + Unpin,
256     T: Into<NciPacket>,
257 {
258     let pkt = rsp.into();
259     let b = pkt.to_bytes();
260     let mut data = BytesMut::with_capacity(b.len() + 2);
261     data.put_u16(b.len().try_into().unwrap());
262     data.extend(b);
263     let frozen = data.freeze();
264     writer.write_all(frozen.as_ref()).await?;
265     debug!("command written");
266     Ok(())
267 }
268