• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "packet_util.h"
18 
19 #include "chpp/app.h"
20 
21 #include <cstring>
22 
23 namespace chpp::test {
24 
25 // Utilities for packet creation -----------------------------------------------
26 
generateEmptyPacket(uint8_t ackSeq,uint8_t seq,uint8_t error)27 ChppEmptyPacket generateEmptyPacket(uint8_t ackSeq, uint8_t seq,
28                                     uint8_t error) {
29   // clang-format off
30   ChppEmptyPacket pkt = {
31     .preamble = kPreamble,
32     .header = {
33       .flags = CHPP_TRANSPORT_FLAG_FINISHED_DATAGRAM,
34       .packetCode = static_cast<uint8_t>(CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
35           CHPP_TRANSPORT_ATTR_NONE, error)),
36       .ackSeq = ackSeq,
37       .seq = seq,
38       .length = 0,
39       .reserved = 0,
40     },
41   };
42   // clang-format on
43   pkt.footer.checksum = computeCrc(pkt);
44   return pkt;
45 }
46 
generateResetPacket(uint8_t ackSeq,uint8_t seq,uint8_t error)47 ChppResetPacket generateResetPacket(uint8_t ackSeq, uint8_t seq,
48                                     uint8_t error) {
49   // clang-format off
50   ChppResetPacket pkt = {
51     .preamble = kPreamble,
52     .header = {
53       .flags = CHPP_TRANSPORT_FLAG_FINISHED_DATAGRAM,
54       .packetCode = static_cast<uint8_t>(CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
55           CHPP_TRANSPORT_ATTR_RESET,
56           error
57       )),
58       .ackSeq = ackSeq,
59       .seq = seq,
60       .length = sizeof(ChppTransportConfiguration),
61       .reserved = 0,
62     },
63     .config = {
64       .version = {
65         .major = 1,
66         .minor = 0,
67         .patch = 0,
68       },
69       .reserved1 = 0,
70       .reserved2 = 0,
71       .reserved3 = 0,
72     }
73   };
74   // clang-format on
75   pkt.footer.checksum = computeCrc(pkt);
76   return pkt;
77 }
78 
generateResetAckPacket(uint8_t ackSeq,uint8_t seq)79 ChppResetPacket generateResetAckPacket(uint8_t ackSeq, uint8_t seq) {
80   ChppResetPacket pkt = generateResetPacket(ackSeq, seq);
81   pkt.header.packetCode =
82       static_cast<uint8_t>(CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
83           CHPP_TRANSPORT_ATTR_RESET_ACK, CHPP_TRANSPORT_ERROR_NONE));
84   pkt.footer.checksum = computeCrc(pkt);
85   return pkt;
86 }
87 
generateAck(const std::vector<uint8_t> & pkt)88 ChppEmptyPacket generateAck(const std::vector<uint8_t> &pkt) {
89   // An ACK consists of an empty packet with the ackSeq set to the received
90   // packet's seq + 1 (since ackSeq indicates the next seq value we expect), and
91   // seq set to the received packet's ackSeq - 1 (since we don't increment seq
92   // on empty packets and ackSeq indicates the next expected seq)
93   const ChppTransportHeader &hdr = getHeader(pkt);
94   return generateEmptyPacket(/*acqSeq=*/hdr.seq + 1, /*seq=*/hdr.ackSeq - 1);
95 }
96 
97 // Utilities for debugging -----------------------------------------------------
98 
appErrorCodeToStr(uint8_t error)99 const char *appErrorCodeToStr(uint8_t error) {
100   switch (error) {
101     case CHPP_APP_ERROR_NONE:
102       return "NONE";
103     case CHPP_APP_ERROR_INVALID_COMMAND:
104       return "INVALID_COMMAND";
105     case CHPP_APP_ERROR_INVALID_ARG:
106       return "INVALID_ARG";
107     case CHPP_APP_ERROR_BUSY:
108       return "BUSY";
109     case CHPP_APP_ERROR_OOM:
110       return "OOM";
111     case CHPP_APP_ERROR_UNSUPPORTED:
112       return "UNSUPPORTED";
113     case CHPP_APP_ERROR_TIMEOUT:
114       return "TIMEOUT";
115     case CHPP_APP_ERROR_DISABLED:
116       return "DISABLED";
117     case CHPP_APP_ERROR_RATELIMITED:
118       return "RATELIMITED";
119     case CHPP_APP_ERROR_BLOCKED:
120       return "BLOCKED";
121     case CHPP_APP_ERROR_INVALID_LENGTH:
122       return "INVALID_LENGTH";
123     case CHPP_APP_ERROR_NOT_READY:
124       return "NOT_READY";
125     case CHPP_APP_ERROR_BEYOND_CHPP:
126       return "BEYOND_CHPP";
127     case CHPP_APP_ERROR_UNEXPECTED_RESPONSE:
128       return "UNEXPECTED_RESPONSE";
129     case CHPP_APP_ERROR_CONVERSION_FAILED:
130       return "CONVERSION_FAILED";
131     case CHPP_APP_ERROR_UNSPECIFIED:
132       return "UNSPECIFIED";
133     default:
134       return "UNKNOWN";
135   }
136 }
137 
appMessageTypeToStr(uint8_t type)138 const char *appMessageTypeToStr(uint8_t type) {
139   switch (type) {
140     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
141       return "CLIENT_REQ";
142     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
143       return "SERVICE_RESP";
144     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION:
145       return "CLIENT_NOTIF";
146     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION:
147       return "SERVICE_NOTIF";
148     case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
149       return "SERVICE_REQ";
150     case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
151       return "CLIENT_RESP";
152     default:
153       return "UNKNOWN";
154   }
155 }
156 
handleToStr(uint8_t handle)157 const char *handleToStr(uint8_t handle) {
158   switch (handle) {
159     case CHPP_HANDLE_NONE:
160       return "(NONE)";
161     case CHPP_HANDLE_LOOPBACK:
162       return "(LOOPBACK)";
163     case CHPP_HANDLE_TIMESYNC:
164       return "(TIMESYNC)";
165     case CHPP_HANDLE_DISCOVERY:
166       return "(DISCOVERY)";
167     default:
168       return "";
169   }
170 }
171 
packetAttrToStr(uint8_t attr)172 const char *packetAttrToStr(uint8_t attr) {
173   switch (attr) {
174     case CHPP_TRANSPORT_ATTR_NONE:
175       return "none";
176     case CHPP_TRANSPORT_ATTR_RESET:
177       return "reset";
178     case CHPP_TRANSPORT_ATTR_RESET_ACK:
179       return "reset-ack";
180     case CHPP_TRANSPORT_ATTR_LOOPBACK_REQUEST:
181       return "loopback-req";
182     case CHPP_TRANSPORT_ATTR_LOOPBACK_RESPONSE:
183       return "loopback-rsp";
184     default:
185       return "invalid";
186   }
187 }
188 
transportErrorToStr(uint8_t error)189 const char *transportErrorToStr(uint8_t error) {
190   switch (error) {
191     case CHPP_TRANSPORT_ERROR_NONE:
192       return "none";
193     case CHPP_TRANSPORT_ERROR_CHECKSUM:
194       return "checksum";
195     case CHPP_TRANSPORT_ERROR_OOM:
196       return "oom";
197     case CHPP_TRANSPORT_ERROR_BUSY:
198       return "busy";
199     case CHPP_TRANSPORT_ERROR_HEADER:
200       return "header";
201     case CHPP_TRANSPORT_ERROR_ORDER:
202       return "order";
203     case CHPP_TRANSPORT_ERROR_TIMEOUT:
204       return "timeout";
205     case CHPP_TRANSPORT_ERROR_MAX_RETRIES:
206       return "max-retries";
207     case CHPP_TRANSPORT_ERROR_APPLAYER:
208       return "app-layer";
209     default:
210       return "invalid";
211   }
212 }
213 
dumpRaw(std::ostream & os,const void * ptr,size_t len)214 void dumpRaw(std::ostream &os, const void *ptr, size_t len) {
215   const uint8_t *buffer = static_cast<const uint8_t *>(ptr);
216   char line[32];
217   char lineChars[32];
218   size_t offset = 0;
219   size_t offsetChars = 0;
220 
221   for (size_t i = 1; i <= len; i++) {
222     // This ignores potential errors returned by snprintf. This is a relatively
223     // simple case and the deliberate decision to ignore them has been made.
224     offset += static_cast<size_t>(
225         snprintf(&line[offset], sizeof(line) - offset, "%02x ", buffer[i - 1]));
226     offsetChars += static_cast<size_t>(
227         snprintf(&lineChars[offsetChars], sizeof(lineChars) - offsetChars, "%c",
228                  (isprint(buffer[i - 1])) ? buffer[i - 1] : '.'));
229     if ((i % 8) == 0) {
230       os << "  " << line << "\t" << lineChars << std::endl;
231       offset = 0;
232       offsetChars = 0;
233     } else if ((i % 4) == 0) {
234       offset += static_cast<size_t>(
235           snprintf(&line[offset], sizeof(line) - offset, " "));
236     }
237   }
238 
239   if (offset > 0) {
240     char tabs[8];
241     char *pos = tabs;
242     while (offset < 28) {
243       *pos++ = '\t';
244       offset += 8;
245     }
246     *pos = '\0';
247     os << "  " << line << tabs << lineChars << std::endl;
248   }
249 }
250 
dumpPreamble(std::ostream & os,uint16_t preamble)251 void dumpPreamble(std::ostream &os, uint16_t preamble) {
252   const char *p = reinterpret_cast<const char *>(&preamble);
253   os << std::endl
254      << "Preamble: 0x" << std::hex << preamble << " \"" << p[0] << p[1] << "\"";
255   if (preamble == kPreamble) {
256     os << " (ok)";
257   } else {
258     os << " (invalid -- expected 0x" << std::hex << kPreamble << ")";
259   }
260   os << std::endl;
261 }
262 
dumpHeader(std::ostream & os,const ChppTransportHeader & hdr)263 void dumpHeader(std::ostream &os, const ChppTransportHeader &hdr) {
264   os << "Header {" << std::endl
265      << "  flags: 0x" << std::hex << (unsigned)hdr.flags;
266   if (hdr.flags & CHPP_TRANSPORT_FLAG_UNFINISHED_DATAGRAM) {
267     os << " (unfinished)";
268   } else {
269     os << " (finished)";
270   }
271   uint8_t attr = CHPP_TRANSPORT_GET_ATTR(hdr.packetCode);
272   uint8_t error = CHPP_TRANSPORT_GET_ERROR(hdr.packetCode);
273   os << std::endl
274      << "  packetCode: 0x" << std::hex << (unsigned)hdr.packetCode
275      << " (attr: " << packetAttrToStr(attr)
276      << " | error: " << transportErrorToStr(error) << ")" << std::endl;
277 
278   os << "  ackSeq: " << std::dec << (unsigned)hdr.ackSeq << std::endl
279      << "  seq: " << std::dec << (unsigned)hdr.seq << std::endl
280      << "  length: " << std::dec << hdr.length << std::endl
281      << "  reserved: " << std::dec << hdr.reserved << std::endl
282      << "}" << std::endl;
283 }
284 
dumpConfig(std::ostream & os,const ChppTransportConfiguration & cfg)285 void dumpConfig(std::ostream &os, const ChppTransportConfiguration &cfg) {
286   os << "Config {" << std::endl
287      << "  version: " << std::dec << (unsigned)cfg.version.major << "."
288      << std::dec << (unsigned)cfg.version.minor << "." << std::dec
289      << cfg.version.patch << std::endl
290      << "}" << std::endl;
291 }
292 
dumpEmptyPacket(std::ostream & os,const ChppEmptyPacket & pkt)293 void dumpEmptyPacket(std::ostream &os, const ChppEmptyPacket &pkt) {
294   dumpPreamble(os, pkt.preamble);
295   dumpHeader(os, pkt.header);
296   dumpFooter(os, pkt);
297 }
298 
dumpResetPacket(std::ostream & os,const ChppResetPacket & pkt)299 void dumpResetPacket(std::ostream &os, const ChppResetPacket &pkt) {
300   dumpPreamble(os, pkt.preamble);
301   dumpHeader(os, pkt.header);
302   dumpConfig(os, pkt.config);
303   dumpFooter(os, pkt);
304 }
305 
dumpPacket(std::ostream & os,const ChppPacketPrefix & pkt)306 void dumpPacket(std::ostream &os, const ChppPacketPrefix &pkt) {
307   dumpPreamble(os, pkt.preamble);
308   dumpHeader(os, pkt.header);
309   size_t payloadOffset = 0;
310   if (CHPP_TRANSPORT_GET_ATTR(pkt.header.packetCode) ==
311           CHPP_TRANSPORT_ATTR_NONE &&
312       pkt.header.length >= sizeof(ChppAppHeader)) {
313     auto &appHdr = reinterpret_cast<const ChppAppHeader &>(*pkt.payload);
314     os << "AppHeader {" << std::endl;
315     os << " handle: 0x" << std::hex << (unsigned)appHdr.handle << " "
316        << handleToStr(appHdr.handle) << std::endl;
317     os << " type: " << std::dec << (unsigned)appHdr.type << " ("
318        << appMessageTypeToStr(appHdr.type) << ")" << std::endl;
319     os << " transaction: " << std::dec << (unsigned)appHdr.transaction
320        << std::endl;
321     os << " error: " << std::dec << (unsigned)appHdr.error << " ("
322        << appErrorCodeToStr(appHdr.error) << ")" << std::endl;
323     os << " command: " << std::dec << (unsigned)appHdr.command << std::endl;
324     os << "}" << std::endl;
325     payloadOffset = sizeof(ChppAppHeader);
326   }
327   size_t payloadSize = pkt.header.length - payloadOffset;
328   if (payloadSize > 0) {
329     os << "Payload (size " << payloadSize << ") {" << std::endl;
330     dumpRaw(os, &pkt.payload[payloadOffset], pkt.header.length - payloadOffset);
331     os << "}" << std::endl;
332   }
333 
334   const auto &footer = *reinterpret_cast<const ChppTransportFooter *>(
335       &pkt.payload[pkt.header.length]);
336   uint32_t crc = chppCrc32(0, reinterpret_cast<const uint8_t *>(&pkt.header),
337                            sizeof(pkt.header) + pkt.header.length);
338   os << "CRC: 0x" << std::hex << footer.checksum;
339   if (footer.checksum != crc) {
340     os << " (invalid, expected " << crc << ")";
341   } else {
342     os << " (ok)";
343   }
344   os << std::endl;
345 }
346 
operator <<(std::ostream & os,const ChppEmptyPacket & pkt)347 std::ostream &operator<<(std::ostream &os, const ChppEmptyPacket &pkt) {
348   dumpEmptyPacket(os, pkt);
349   return os;
350 }
351 
operator <<(std::ostream & os,const ChppResetPacket & pkt)352 std::ostream &operator<<(std::ostream &os, const ChppResetPacket &pkt) {
353   dumpResetPacket(os, pkt);
354   return os;
355 }
356 
operator <<(std::ostream & os,const ChppPacketPrefix & pkt)357 std::ostream &operator<<(std::ostream &os, const ChppPacketPrefix &pkt) {
358   dumpPacket(os, pkt);
359   return os;
360 }
361 
362 // Utilities for gtest packet checking -----------------------------------------
363 
checkPacketValidity(std::vector<uint8_t> & received)364 void checkPacketValidity(std::vector<uint8_t> &received) {
365   const ChppPacketPrefix &pkt = asChpp(received);
366   EXPECT_GE(received.size(), sizeof(ChppEmptyPacket));
367   EXPECT_EQ(pkt.preamble, kPreamble);
368 
369   constexpr size_t kFixedLenPortion =
370       sizeof(pkt.preamble) + sizeof(pkt.header) + sizeof(ChppTransportFooter);
371   EXPECT_EQ(pkt.header.length, received.size() - kFixedLenPortion);
372 
373   EXPECT_EQ(pkt.header.flags & CHPP_TRANSPORT_FLAG_RESERVED, 0);
374   EXPECT_EQ(pkt.header.reserved, 0);
375 
376   uint8_t error = CHPP_TRANSPORT_GET_ERROR(pkt.header.packetCode);
377   EXPECT_TRUE(error <= CHPP_TRANSPORT_SIGNAL_FORCE_RESET ||
378               error == CHPP_TRANSPORT_ERROR_APPLAYER);
379   uint8_t attrs = CHPP_TRANSPORT_GET_ATTR(pkt.header.packetCode);
380   EXPECT_TRUE(attrs <= CHPP_TRANSPORT_ATTR_LOOPBACK_RESPONSE);
381 
382   uint32_t crc = chppCrc32(0, reinterpret_cast<const uint8_t *>(&pkt.header),
383                            sizeof(pkt.header) + pkt.header.length);
384   const auto *footer = reinterpret_cast<const ChppTransportFooter *>(
385       &received[sizeof(pkt.preamble) + sizeof(pkt.header) + pkt.header.length]);
386   EXPECT_EQ(footer->checksum, crc);
387 }
388 
comparePacketHeader(const ChppTransportHeader & rx,const ChppTransportHeader & expected)389 bool comparePacketHeader(const ChppTransportHeader &rx,
390                          const ChppTransportHeader &expected) {
391   EXPECT_EQ(rx.flags, expected.flags);
392   EXPECT_EQ(rx.packetCode, expected.packetCode);
393   EXPECT_EQ(rx.ackSeq, expected.ackSeq);
394   EXPECT_EQ(rx.seq, expected.seq);
395   EXPECT_EQ(rx.length, expected.length);
396   EXPECT_EQ(rx.reserved, 0u);
397   return (memcmp(&rx, &expected, sizeof(rx)) == 0);
398 }
399 
comparePacket(const std::vector<uint8_t> & received,const ChppEmptyPacket & expected)400 bool comparePacket(const std::vector<uint8_t> &received,
401                    const ChppEmptyPacket &expected) {
402   EXPECT_EQ(received.size(), sizeof(expected));
403   if (received.size() == sizeof(expected)) {
404     const auto *rx = reinterpret_cast<const ChppEmptyPacket *>(received.data());
405     EXPECT_EQ(rx->preamble, expected.preamble);
406     comparePacketHeader(rx->header, expected.header);
407     EXPECT_EQ(rx->footer.checksum, expected.footer.checksum);
408   }
409   return (received.size() == sizeof(expected) &&
410           memcmp(received.data(), &expected, sizeof(expected)) == 0);
411 }
412 
comparePacket(const std::vector<uint8_t> & received,const ChppResetPacket & expected)413 bool comparePacket(const std::vector<uint8_t> &received,
414                    const ChppResetPacket &expected) {
415   EXPECT_EQ(received.size(), sizeof(expected));
416   if (received.size() == sizeof(expected)) {
417     const auto *rx = reinterpret_cast<const ChppResetPacket *>(received.data());
418     EXPECT_EQ(rx->preamble, expected.preamble);
419     comparePacketHeader(rx->header, expected.header);
420     EXPECT_EQ(rx->config.version.major, expected.config.version.major);
421     EXPECT_EQ(rx->config.version.minor, expected.config.version.minor);
422     EXPECT_EQ(rx->config.version.patch, expected.config.version.patch);
423     EXPECT_EQ(rx->footer.checksum, expected.footer.checksum);
424   }
425   return (received.size() == sizeof(expected) &&
426           memcmp(received.data(), &expected, sizeof(expected)) == 0);
427 }
428 
429 }  // namespace chpp::test