1 // Copyright 2023, 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 //! Packet parsers and serializers. 16 17 /// NCI packet parser and serializer. 18 pub mod nci { 19 #![allow(clippy::all)] 20 #![allow(unused)] 21 #![allow(missing_docs)] 22 23 include!(concat!(env!("OUT_DIR"), "/nci_packets.rs")); 24 25 impl ConnId { 26 /// Create a Conn ID with `id` as an offset in the range of dynamic 27 /// identifiers. from_dynamic(id: u8) -> Self28 pub fn from_dynamic(id: u8) -> Self { 29 ConnId::try_from(id as u8 + 2).unwrap() 30 } 31 32 /// Return the index for a dynamic Conn ID. to_dynamic(id: Private<u8>) -> u833 pub fn to_dynamic(id: Private<u8>) -> u8 { 34 *id - 2 35 } 36 } 37 38 impl RfDiscoveryId { 39 /// Create the default reserved RF Discovery ID. reserved() -> Self40 pub fn reserved() -> Self { 41 RfDiscoveryId::try_from(0).unwrap() 42 } 43 44 /// Create an RF Discovery ID with `id` as an offset in the range of 45 /// non-reserved identifiers. from_index(id: usize) -> Self46 pub fn from_index(id: usize) -> Self { 47 RfDiscoveryId::try_from(id as u8 + 1).unwrap() 48 } 49 50 /// Return the index for a valid RF Discovery ID. to_index(id: Private<u8>) -> usize51 pub fn to_index(id: Private<u8>) -> usize { 52 *id as usize - 1 53 } 54 } 55 56 impl NfceeId { nfcee(id: u8) -> Self57 pub fn nfcee(id: u8) -> Self { 58 NfceeId::try_from(id).unwrap() 59 } 60 hci_nfcee(id: u8) -> Self61 pub fn hci_nfcee(id: u8) -> Self { 62 NfceeId::try_from(id).unwrap() 63 } 64 } 65 66 use futures::stream::{self, Stream}; 67 use std::pin::Pin; 68 use tokio::io::{AsyncRead, AsyncWrite}; 69 use tokio::sync::Mutex; 70 71 /// Read NCI Control and Data packets received on the NCI transport. 72 /// Performs recombination of the segmented packets. 73 pub struct Reader { 74 socket: Pin<Box<dyn AsyncRead>>, 75 } 76 77 /// Write NCI Control and Data packets received to the NCI transport. 78 /// Performs segmentation of the packets. 79 pub struct Writer { 80 socket: Pin<Box<dyn AsyncWrite>>, 81 } 82 83 impl Reader { 84 /// Create an NCI reader from an NCI transport. new<T: AsyncRead + 'static>(rx: T) -> Self85 pub fn new<T: AsyncRead + 'static>(rx: T) -> Self { 86 Reader { socket: Box::pin(rx) } 87 } 88 89 /// Read a single NCI packet from the reader. The packet is automatically 90 /// re-assembled if segmented on the NCI transport. read(&mut self) -> anyhow::Result<Vec<u8>>91 pub async fn read(&mut self) -> anyhow::Result<Vec<u8>> { 92 use tokio::io::AsyncReadExt; 93 94 const HEADER_SIZE: usize = 3; 95 let mut complete_packet = vec![0; HEADER_SIZE]; 96 97 // Note on reassembly: 98 // - for each segment of a Control Message, the header of the 99 // Control Packet SHALL contain the same MT, GID and OID values, 100 // - for each segment of a Data Message the header of the Data 101 // Packet SHALL contain the same MT and Conn ID. 102 // Thus it is correct to keep only the last header of the segmented 103 // packet. 104 loop { 105 // Read the common packet header. 106 self.socket.read_exact(&mut complete_packet[0..HEADER_SIZE]).await?; 107 let header = PacketHeader::parse(&complete_packet[0..HEADER_SIZE])?; 108 109 // Read the packet payload. 110 let payload_length = header.get_payload_length() as usize; 111 let mut payload_bytes = vec![0; payload_length]; 112 self.socket.read_exact(&mut payload_bytes).await?; 113 complete_packet.extend(payload_bytes); 114 115 // Check the Packet Boundary Flag. 116 match header.get_pbf() { 117 PacketBoundaryFlag::CompleteOrFinal => return Ok(complete_packet), 118 PacketBoundaryFlag::Incomplete => (), 119 } 120 } 121 } 122 into_stream(self) -> impl Stream<Item = anyhow::Result<Vec<u8>>>123 pub fn into_stream(self) -> impl Stream<Item = anyhow::Result<Vec<u8>>> { 124 stream::try_unfold(self, |mut reader| async move { 125 Ok(Some((reader.read().await?, reader))) 126 }) 127 } 128 } 129 130 /// A mutable reference to the stream returned by into_stream 131 pub type StreamRefMut<'a> = Pin<&'a mut dyn Stream<Item = anyhow::Result<Vec<u8>>>>; 132 133 impl Writer { 134 /// Create an NCI writer from an NCI transport. new<T: AsyncWrite + 'static>(rx: T) -> Self135 pub fn new<T: AsyncWrite + 'static>(rx: T) -> Self { 136 Writer { socket: Box::pin(rx) } 137 } 138 139 /// Write a single NCI packet to the writer. The packet is automatically 140 /// segmented if the payload exceeds the maximum size limit. write(&mut self, mut packet: &[u8]) -> anyhow::Result<()>141 pub async fn write(&mut self, mut packet: &[u8]) -> anyhow::Result<()> { 142 use tokio::io::AsyncWriteExt; 143 144 let mut header_bytes = [packet[0], packet[1], 0]; 145 packet = &packet[3..]; 146 147 loop { 148 // Update header with framing information. 149 let chunk_length = std::cmp::min(255, packet.len()); 150 let pbf = if chunk_length < packet.len() { 151 PacketBoundaryFlag::Incomplete 152 } else { 153 PacketBoundaryFlag::CompleteOrFinal 154 }; 155 const PBF_MASK: u8 = 0x10; 156 header_bytes[0] &= !PBF_MASK; 157 header_bytes[0] |= (pbf as u8) << 4; 158 header_bytes[2] = chunk_length as u8; 159 160 // Write the header and payload segment bytes. 161 self.socket.write_all(&header_bytes).await?; 162 self.socket.write_all(&packet[..chunk_length]).await?; 163 packet = &packet[chunk_length..]; 164 165 if packet.is_empty() { 166 return Ok(()); 167 } 168 } 169 } 170 } 171 } 172 173 /// RF packet parser and serializer. 174 pub mod rf { 175 #![allow(clippy::all)] 176 #![allow(unused)] 177 #![allow(missing_docs)] 178 179 include!(concat!(env!("OUT_DIR"), "/rf_packets.rs")); 180 } 181 182 impl From<rf::Protocol> for nci::RfProtocolType { from(protocol: rf::Protocol) -> Self183 fn from(protocol: rf::Protocol) -> Self { 184 match protocol { 185 rf::Protocol::Undetermined => nci::RfProtocolType::Undetermined, 186 rf::Protocol::T1t => nci::RfProtocolType::T1t, 187 rf::Protocol::T2t => nci::RfProtocolType::T2t, 188 rf::Protocol::T3t => nci::RfProtocolType::T3t, 189 rf::Protocol::IsoDep => nci::RfProtocolType::IsoDep, 190 rf::Protocol::NfcDep => nci::RfProtocolType::NfcDep, 191 rf::Protocol::T5t => nci::RfProtocolType::T5t, 192 rf::Protocol::Ndef => nci::RfProtocolType::Ndef, 193 } 194 } 195 } 196 197 impl From<nci::RfProtocolType> for rf::Protocol { from(protocol: nci::RfProtocolType) -> Self198 fn from(protocol: nci::RfProtocolType) -> Self { 199 match protocol { 200 nci::RfProtocolType::Undetermined => rf::Protocol::Undetermined, 201 nci::RfProtocolType::T1t => rf::Protocol::T1t, 202 nci::RfProtocolType::T2t => rf::Protocol::T2t, 203 nci::RfProtocolType::T3t => rf::Protocol::T3t, 204 nci::RfProtocolType::IsoDep => rf::Protocol::IsoDep, 205 nci::RfProtocolType::NfcDep => rf::Protocol::NfcDep, 206 nci::RfProtocolType::T5t => rf::Protocol::T5t, 207 nci::RfProtocolType::Ndef => rf::Protocol::Ndef, 208 } 209 } 210 } 211 212 impl TryFrom<nci::RfTechnologyAndMode> for rf::Technology { 213 type Error = nci::RfTechnologyAndMode; try_from(protocol: nci::RfTechnologyAndMode) -> Result<Self, Self::Error>214 fn try_from(protocol: nci::RfTechnologyAndMode) -> Result<Self, Self::Error> { 215 Ok(match protocol { 216 nci::RfTechnologyAndMode::NfcAPassivePollMode 217 | nci::RfTechnologyAndMode::NfcAPassiveListenMode => rf::Technology::NfcA, 218 nci::RfTechnologyAndMode::NfcBPassivePollMode 219 | nci::RfTechnologyAndMode::NfcBPassiveListenMode => rf::Technology::NfcB, 220 nci::RfTechnologyAndMode::NfcFPassivePollMode 221 | nci::RfTechnologyAndMode::NfcFPassiveListenMode => rf::Technology::NfcF, 222 nci::RfTechnologyAndMode::NfcVPassivePollMode => rf::Technology::NfcV, 223 _ => return Err(protocol), 224 }) 225 } 226 } 227 228 impl From<rf::DeactivateType> for nci::DeactivationType { from(type_: rf::DeactivateType) -> Self229 fn from(type_: rf::DeactivateType) -> Self { 230 match type_ { 231 rf::DeactivateType::IdleMode => nci::DeactivationType::IdleMode, 232 rf::DeactivateType::SleepMode => nci::DeactivationType::SleepMode, 233 rf::DeactivateType::SleepAfMode => nci::DeactivationType::SleepAfMode, 234 rf::DeactivateType::Discovery => nci::DeactivationType::Discovery, 235 } 236 } 237 } 238 239 impl From<nci::DeactivationType> for rf::DeactivateType { from(type_: nci::DeactivationType) -> Self240 fn from(type_: nci::DeactivationType) -> Self { 241 match type_ { 242 nci::DeactivationType::IdleMode => rf::DeactivateType::IdleMode, 243 nci::DeactivationType::SleepMode => rf::DeactivateType::SleepMode, 244 nci::DeactivationType::SleepAfMode => rf::DeactivateType::SleepAfMode, 245 nci::DeactivationType::Discovery => rf::DeactivateType::Discovery, 246 } 247 } 248 } 249 250 impl From<rf::DeactivateReason> for nci::DeactivationReason { from(reason: rf::DeactivateReason) -> Self251 fn from(reason: rf::DeactivateReason) -> Self { 252 match reason { 253 rf::DeactivateReason::DhRequest => nci::DeactivationReason::DhRequest, 254 rf::DeactivateReason::EndpointRequest => nci::DeactivationReason::EndpointRequest, 255 rf::DeactivateReason::RfLinkLoss => nci::DeactivationReason::RfLinkLoss, 256 rf::DeactivateReason::NfcBBadAfi => nci::DeactivationReason::NfcBBadAfi, 257 rf::DeactivateReason::DhRequestFailed => nci::DeactivationReason::DhRequestFailed, 258 } 259 } 260 } 261