1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <fcntl.h>
18 #include <chrono>
19 #include <cstdint>
20 
21 #include "casimir_controller.h"
22 
23 namespace cuttlefish {
24 
25 using namespace casimir::rf;
26 using namespace std::literals::chrono_literals;
27 using pdl::packet::slice;
28 
Mute()29 Result<void> CasimirController::Mute() {
30   if (!sock_->IsOpen()) {
31     return {};
32   }
33   FieldInfoBuilder rf_off;
34   rf_off.field_status_ = FieldStatus::FieldOff;
35   rf_off.power_level_ = power_level;
36   CF_EXPECT(Write(rf_off));
37   return {};
38 }
39 
CasimirController(SharedFD sock)40 CasimirController::CasimirController(SharedFD sock)
41     : sock_(sock), power_level(10) {}
42 
43 /* static */
ConnectToTcpPort(int rf_port)44 Result<CasimirController> CasimirController::ConnectToTcpPort(int rf_port) {
45   SharedFD sock = SharedFD::SocketLocalClient(rf_port, SOCK_STREAM);
46   CF_EXPECT(sock->IsOpen(),
47             "Failed to connect to casimir with RF port" << rf_port);
48 
49   int flags = sock->Fcntl(F_GETFL, 0);
50   CF_EXPECT_GE(flags, 0, "Failed to get FD flags of casimir socket");
51   CF_EXPECT_EQ(sock->Fcntl(F_SETFL, flags | O_NONBLOCK), 0,
52                "Failed to set casimir socket nonblocking");
53 
54   return CasimirController(sock);
55 }
56 
57 /* static */
ConnectToUnixSocket(const std::string & rf_path)58 Result<CasimirController> CasimirController::ConnectToUnixSocket(
59     const std::string& rf_path) {
60   SharedFD sock = SharedFD::SocketLocalClient(rf_path, false, SOCK_STREAM);
61   CF_EXPECT(sock->IsOpen(),
62             "Failed to connect to casimir with RF path" << rf_path);
63 
64   int flags = sock->Fcntl(F_GETFL, 0);
65   CF_EXPECT_GE(flags, 0, "Failed to get FD flags of casimir socket");
66   CF_EXPECT_EQ(sock->Fcntl(F_SETFL, flags | O_NONBLOCK), 0,
67                "Failed to set casimir socket nonblocking");
68   return CasimirController(sock);
69 }
70 
Unmute()71 Result<void> CasimirController::Unmute() {
72   if (!sock_->IsOpen()) {
73     return {};
74   }
75   FieldInfoBuilder rf_on;
76   rf_on.field_status_ = FieldStatus::FieldOn;
77   rf_on.power_level_ = power_level;
78   CF_EXPECT(Write(rf_on));
79   return {};
80 }
81 
SetPowerLevel(uint32_t power_level)82 Result<void> CasimirController::SetPowerLevel(uint32_t power_level) {
83   this->power_level = power_level;
84   return {};
85 }
86 
SelectNfcA()87 Result<uint16_t> CasimirController::SelectNfcA() {
88   PollCommandBuilder poll_command;
89   poll_command.technology_ = Technology::NFC_A;
90   poll_command.power_level_ = power_level;
91   CF_EXPECT(Write(poll_command), "Failed to send NFC-A poll command");
92 
93   auto res = CF_EXPECT(ReadRfPacket(10s), "Failed to get NFC-A poll response");
94 
95   auto rf_packet = RfPacketView::Create(slice(res));
96   if (rf_packet.IsValid()) {
97     auto poll_response = NfcAPollResponseView::Create(rf_packet);
98     if (poll_response.IsValid() && poll_response.GetIntProtocol() == 0b01) {
99       return poll_response.GetSender();
100     }
101   }
102   return CF_ERR("Invalid Poll-A response");
103 }
104 
SelectT4AT(uint16_t sender_id)105 Result<void> CasimirController::SelectT4AT(uint16_t sender_id) {
106   T4ATSelectCommandBuilder t4at_select_command;
107   t4at_select_command.sender_ = sender_id;
108   t4at_select_command.param_ = 0;
109   CF_EXPECT(Write(t4at_select_command), "Failed to send T4AT select command");
110 
111   auto res = CF_EXPECT(ReadRfPacket(1s), "Failed to get T4AT response");
112 
113   // Note: T4AT select response implies NFC_A and ISO_DEP
114   auto rf_packet = RfPacketView::Create(slice(res));
115   if (rf_packet.IsValid()) {
116     auto select_response = T4ATSelectResponseView::Create(rf_packet);
117     if (select_response.IsValid() && select_response.GetSender() == sender_id) {
118       return {};
119     }
120   }
121   return CF_ERR("Invalid T4AT response");
122 }
123 
Poll()124 Result<uint16_t> CasimirController::Poll() {
125   CF_EXPECT(sock_->IsOpen());
126 
127   uint16_t sender_id = CF_EXPECT(SelectNfcA(), "Failed to select NFC-A");
128   CF_EXPECT(SelectT4AT(sender_id), "Failed to select T4AT");
129   return sender_id;
130 }
131 
SendApdu(uint16_t receiver_id,std::vector<uint8_t> apdu)132 Result<std::vector<uint8_t>> CasimirController::SendApdu(
133     uint16_t receiver_id, std::vector<uint8_t> apdu) {
134   CF_EXPECT(sock_->IsOpen());
135 
136   DataBuilder data_builder;
137   data_builder.data_ = std::move(apdu);
138   data_builder.receiver_ = receiver_id;
139   data_builder.technology_ = Technology::NFC_A;
140   data_builder.protocol_ = Protocol::ISO_DEP;
141 
142   CF_EXPECT(Write(data_builder), "Failed to send APDU bytes");
143 
144   auto res = CF_EXPECT(ReadRfPacket(3s), "Failed to get APDU response");
145   auto rf_packet = RfPacketView::Create(slice(res));
146   if (rf_packet.IsValid()) {
147     auto data = DataView::Create(rf_packet);
148     if (data.IsValid() && rf_packet.GetSender() == receiver_id) {
149       return data.GetData();
150     }
151   }
152   return CF_ERR("Invalid APDU response");
153 }
154 
Write(const RfPacketBuilder & rf_packet)155 Result<void> CasimirController::Write(const RfPacketBuilder& rf_packet) {
156   std::vector<uint8_t> raw_bytes = rf_packet.SerializeToBytes();
157   uint16_t header_bytes_le = htole16(raw_bytes.size());
158   ssize_t written = WriteAll(sock_, reinterpret_cast<char*>(&header_bytes_le),
159                              sizeof(header_bytes_le));
160   CF_EXPECT_EQ(written, sizeof(header_bytes_le),
161                "Failed to write packet header to casimir socket, errno="
162                    << sock_->GetErrno());
163 
164   written = WriteAll(sock_, reinterpret_cast<char*>(raw_bytes.data()),
165                      raw_bytes.size());
166   CF_EXPECT_EQ(written, raw_bytes.size(),
167                "Failed to write packet payload to casimir socket, errno="
168                    << sock_->GetErrno());
169 
170   return {};
171 }
172 
ReadExact(size_t size,std::chrono::milliseconds timeout)173 Result<std::shared_ptr<std::vector<uint8_t>>> CasimirController::ReadExact(
174     size_t size, std::chrono::milliseconds timeout) {
175   size_t total_read = 0;
176   auto out = std::make_shared<std::vector<uint8_t>>(size);
177   auto prev_time = std::chrono::steady_clock::now();
178   while (timeout.count() > 0) {
179     PollSharedFd poll_fd = {
180         .fd = sock_,
181         .events = EPOLLIN,
182         .revents = 0,
183     };
184     int res = sock_.Poll(&poll_fd, 1, timeout.count());
185     CF_EXPECT_GE(res, 0, "Failed to poll on the casimir socket");
186     CF_EXPECT_EQ(poll_fd.revents, EPOLLIN,
187                  "Unexpected poll result for reading");
188 
189     // Nonblocking read, so don't need to care about timeout.
190     ssize_t read =
191         sock_->Read((void*)&(out->data()[total_read]), size - total_read);
192     CF_EXPECT_GT(
193         read, 0,
194         "Failed to read from casimir socket, errno=" << sock_->GetErrno());
195 
196     total_read += read;
197     if (total_read >= size) {
198       return out;
199     }
200 
201     auto current_time = std::chrono::steady_clock::now();
202     timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(
203         current_time - prev_time);
204   }
205 
206   return CF_ERR("Failed to read from casimir socket; timed out");
207 }
208 
209 // Note: Although rf_packets.h doesn't document nor include packet header,
210 // the header is necessary to know total packet size.
ReadRfPacket(std::chrono::milliseconds timeout)211 Result<std::shared_ptr<std::vector<uint8_t>>> CasimirController::ReadRfPacket(
212     std::chrono::milliseconds timeout) {
213   auto start_time = std::chrono::steady_clock::now();
214 
215   auto res = CF_EXPECT(ReadExact(sizeof(uint16_t), timeout),
216                        "Failed to read RF packet header");
217   slice packet_size_slice(res);
218   int16_t packet_size = packet_size_slice.read_le<uint16_t>();
219 
220   auto current_time = std::chrono::steady_clock::now();
221   timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(
222       current_time - start_time);
223   return CF_EXPECT(ReadExact(packet_size, timeout),
224                    "Failed to read RF packet payload");
225 }
226 
227 }  // namespace cuttlefish
228