1 /*
2 * Copyright (C) 2020 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 "transport_test.h"
18
19 #include <gtest/gtest.h>
20
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <chrono>
26 #include <thread>
27
28 #include "chpp/app.h"
29 #include "chpp/common/discovery.h"
30 #include "chpp/common/gnss.h"
31 #include "chpp/common/gnss_types.h"
32 #include "chpp/common/standard_uuids.h"
33 #include "chpp/common/wifi.h"
34 #include "chpp/common/wifi_types.h"
35 #include "chpp/common/wwan.h"
36 #include "chpp/crc.h"
37 #include "chpp/macros.h"
38 #include "chpp/memory.h"
39 #include "chpp/platform/platform_link.h"
40 #include "chpp/platform/utils.h"
41 #include "chpp/services/discovery.h"
42 #include "chpp/services/loopback.h"
43 #include "chpp/transport.h"
44 #include "chre/pal/wwan.h"
45
46 namespace chpp::test {
47
48 namespace {
49
50 // Max size of payload sent to chppRxDataCb (bytes)
51 constexpr size_t kMaxChunkSize = 20000;
52
53 constexpr size_t kMaxPacketSize =
54 kMaxChunkSize + CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES;
55
56 // Input sizes to test the entire range of sizes with a few tests
57 constexpr int kChunkSizes[] = {0, 1, 2, 3, 4, 21, 100, 1000, 10001, 20000};
58
59 // Number of services
60 constexpr int kServiceCount = CHPP_EXPECTED_SERVICE_COUNT;
61
62 // State of the link layer.
63 struct ChppLinuxLinkState gChppLinuxLinkContext;
64
65 } // namespace
66
67 /*
68 * Test suite for the CHPP Transport Layer
69 */
70 class TransportTests : public testing::TestWithParam<int> {
71 protected:
SetUp()72 void SetUp() override {
73 chppClearTotalAllocBytes();
74 memset(&gChppLinuxLinkContext, 0, sizeof(struct ChppLinuxLinkState));
75 gChppLinuxLinkContext.linkEstablished = true;
76 gChppLinuxLinkContext.isLinkActive = true;
77 const struct ChppLinkApi *linkApi = getLinuxLinkApi();
78 chppTransportInit(&mTransportContext, &mAppContext, &gChppLinuxLinkContext,
79 linkApi);
80 chppAppInit(&mAppContext, &mTransportContext);
81
82 mTransportContext.resetState = CHPP_RESET_STATE_NONE;
83
84 // Make sure CHPP has a correct count of the number of registered services
85 // on this platform as registered in the function
86 // chppRegisterCommonServices().
87 ASSERT_EQ(mAppContext.registeredServiceCount, kServiceCount);
88 }
89
TearDown()90 void TearDown() override {
91 chppAppDeinit(&mAppContext);
92 chppTransportDeinit(&mTransportContext);
93
94 EXPECT_EQ(chppGetTotalAllocBytes(), 0);
95 }
96
97 ChppTransportState mTransportContext = {};
98 ChppAppState mAppContext = {};
99 uint8_t mBuf[kMaxPacketSize] = {};
100 };
101
102 /**
103 * A series of zeros shouldn't change state from CHPP_STATE_PREAMBLE
104 */
TEST_P(TransportTests,ZeroNoPreambleInput)105 TEST_P(TransportTests, ZeroNoPreambleInput) {
106 size_t len = static_cast<size_t>(GetParam());
107 if (len <= kMaxChunkSize) {
108 EXPECT_TRUE(chppRxDataCb(&mTransportContext, mBuf, len));
109 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PREAMBLE);
110 }
111 }
112
113 /**
114 * A preamble after a series of zeros input should change state from
115 * CHPP_STATE_PREAMBLE to CHPP_STATE_HEADER
116 */
TEST_P(TransportTests,ZeroThenPreambleInput)117 TEST_P(TransportTests, ZeroThenPreambleInput) {
118 size_t len = static_cast<size_t>(GetParam());
119
120 if (len <= kMaxChunkSize) {
121 // Add preamble at the end of mBuf, as individual bytes instead of using
122 // chppAddPreamble(&mBuf[preambleLoc])
123 size_t preambleLoc = MAX(0, len - CHPP_PREAMBLE_LEN_BYTES);
124 mBuf[preambleLoc] = kChppPreamble0;
125 mBuf[preambleLoc + 1] = kChppPreamble1;
126
127 if (len >= CHPP_PREAMBLE_LEN_BYTES) {
128 EXPECT_FALSE(chppRxDataCb(&mTransportContext, mBuf, len));
129 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_HEADER);
130 } else {
131 EXPECT_TRUE(chppRxDataCb(&mTransportContext, mBuf, len));
132 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PREAMBLE);
133 }
134 }
135 }
136
137 /**
138 * Rx Testing with various length payloads of zeros
139 */
TEST_P(TransportTests,RxPayloadOfZeros)140 TEST_P(TransportTests, RxPayloadOfZeros) {
141 mTransportContext.rxStatus.state = CHPP_STATE_PREAMBLE;
142 size_t len = static_cast<size_t>(GetParam());
143 bool isLenValid = (len <= chppTransportRxMtuSize(&mTransportContext));
144
145 std::thread t1(chppWorkThreadStart, &mTransportContext);
146 waitForLinkSendDone();
147
148 if (len <= kMaxChunkSize) {
149 size_t loc = 0;
150 addPreambleToBuf(mBuf, &loc);
151 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &loc);
152
153 transHeader->length = static_cast<uint16_t>(len);
154 loc += len;
155
156 addTransportFooterToBuf(mBuf, &loc);
157
158 // Send header and check for correct state
159 EXPECT_EQ(
160 chppRxDataCb(&mTransportContext, mBuf,
161 CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader)),
162 !isLenValid);
163
164 if (!isLenValid) {
165 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PREAMBLE);
166 } else if (len > 0) {
167 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PAYLOAD);
168 } else {
169 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_FOOTER);
170 }
171
172 // Correct decoding of packet length
173 EXPECT_EQ(mTransportContext.rxHeader.length, len);
174 EXPECT_EQ(mTransportContext.rxStatus.locInDatagram, 0);
175 EXPECT_EQ(mTransportContext.rxDatagram.length, isLenValid ? len : 0);
176
177 // Send payload if any and check for correct state
178 if (len > 0) {
179 EXPECT_EQ(
180 chppRxDataCb(
181 &mTransportContext,
182 &mBuf[CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader)],
183 len),
184 !isLenValid);
185 EXPECT_EQ(mTransportContext.rxStatus.state,
186 isLenValid ? CHPP_STATE_FOOTER : CHPP_STATE_PREAMBLE);
187 }
188
189 // Should have complete packet payload by now
190 EXPECT_EQ(mTransportContext.rxStatus.locInDatagram, isLenValid ? len : 0);
191
192 // But no ACK yet
193 EXPECT_EQ(mTransportContext.rxStatus.expectedSeq, transHeader->seq);
194
195 // Send footer
196 EXPECT_TRUE(chppRxDataCb(
197 &mTransportContext,
198 &mBuf[CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) + len],
199 sizeof(ChppTransportFooter)));
200
201 // The next expected packet sequence # should incremented only if the
202 // received packet is payload-bearing.
203 uint8_t nextSeq = transHeader->seq + ((isLenValid && len > 0) ? 1 : 0);
204 EXPECT_EQ(mTransportContext.rxStatus.expectedSeq, nextSeq);
205
206 // Check for correct ACK crafting if applicable (i.e. if the received packet
207 // is payload-bearing).
208 if (isLenValid && len > 0) {
209 EXPECT_EQ(mTransportContext.txStatus.packetCodeToSend,
210 CHPP_TRANSPORT_ERROR_NONE);
211 EXPECT_EQ(mTransportContext.txDatagramQueue.pending, 0);
212
213 waitForLinkSendDone();
214
215 // Check response packet fields
216 struct ChppTransportHeader *txHeader =
217 (struct ChppTransportHeader *)&gChppLinuxLinkContext
218 .buf[CHPP_PREAMBLE_LEN_BYTES];
219 EXPECT_EQ(txHeader->flags, CHPP_TRANSPORT_FLAG_FINISHED_DATAGRAM);
220 EXPECT_EQ(txHeader->packetCode, CHPP_TRANSPORT_ERROR_NONE);
221 EXPECT_EQ(txHeader->ackSeq, nextSeq);
222 EXPECT_EQ(txHeader->length, 0);
223
224 // Check outgoing packet length
225 EXPECT_EQ(mTransportContext.linkBufferSize,
226 CHPP_PREAMBLE_LEN_BYTES + sizeof(struct ChppTransportHeader) +
227 sizeof(struct ChppTransportFooter));
228 }
229
230 // Check for correct state
231 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PREAMBLE);
232
233 // Should have reset loc and length for next packet / datagram
234 EXPECT_EQ(mTransportContext.rxStatus.locInDatagram, 0);
235 EXPECT_EQ(mTransportContext.rxDatagram.length, 0);
236 }
237
238 chppWorkThreadStop(&mTransportContext);
239 t1.join();
240 }
241
242 /**
243 * End of Packet Link Notification during preamble
244 */
TEST_F(TransportTests,LinkSendDonePreamble)245 TEST_F(TransportTests, LinkSendDonePreamble) {
246 size_t payloadLen = 1000;
247 size_t partLenPreamble = CHPP_PREAMBLE_LEN_BYTES - 1;
248
249 mTransportContext.rxStatus.state = CHPP_STATE_PREAMBLE;
250 std::thread t1(chppWorkThreadStart, &mTransportContext);
251 waitForLinkSendDone();
252
253 size_t loc = 0;
254 addPreambleToBuf(mBuf, &loc);
255 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &loc);
256 transHeader->length = static_cast<uint16_t>(payloadLen);
257 loc += payloadLen;
258 addTransportFooterToBuf(mBuf, &loc);
259
260 EXPECT_FALSE(chppRxDataCb(&mTransportContext, mBuf, partLenPreamble));
261 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PREAMBLE);
262 endAndValidatePacket(&mTransportContext);
263
264 chppWorkThreadStop(&mTransportContext);
265 t1.join();
266 }
267
268 /**
269 * End of Packet Link Notification during header
270 */
TEST_F(TransportTests,LinkSendDoneHeader)271 TEST_F(TransportTests, LinkSendDoneHeader) {
272 size_t payloadLen = 1000;
273 size_t partLenHeader =
274 CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) - 1;
275
276 mTransportContext.rxStatus.state = CHPP_STATE_PREAMBLE;
277 std::thread t1(chppWorkThreadStart, &mTransportContext);
278 waitForLinkSendDone();
279
280 size_t loc = 0;
281 addPreambleToBuf(mBuf, &loc);
282 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &loc);
283 transHeader->length = static_cast<uint16_t>(payloadLen);
284 loc += payloadLen;
285 addTransportFooterToBuf(mBuf, &loc);
286
287 EXPECT_FALSE(chppRxDataCb(&mTransportContext, mBuf, partLenHeader));
288 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_HEADER);
289 EXPECT_EQ(mTransportContext.rxHeader.length, payloadLen);
290 endAndValidatePacket(&mTransportContext);
291
292 chppWorkThreadStop(&mTransportContext);
293 t1.join();
294 }
295
296 /**
297 * End of Packet Link Notification during payload
298 */
TEST_F(TransportTests,LinkSendDonePayload)299 TEST_F(TransportTests, LinkSendDonePayload) {
300 size_t payloadLen = 1000;
301 size_t partLenPayload = 500;
302
303 mTransportContext.rxStatus.state = CHPP_STATE_PREAMBLE;
304 std::thread t1(chppWorkThreadStart, &mTransportContext);
305 waitForLinkSendDone();
306
307 size_t loc = 0;
308 addPreambleToBuf(mBuf, &loc);
309 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &loc);
310 transHeader->length = static_cast<uint16_t>(payloadLen);
311 loc += payloadLen;
312 addTransportFooterToBuf(mBuf, &loc);
313
314 EXPECT_FALSE(chppRxDataCb(&mTransportContext, mBuf, partLenPayload));
315 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PAYLOAD);
316 EXPECT_EQ(mTransportContext.rxHeader.length, payloadLen);
317 EXPECT_EQ(
318 mTransportContext.rxStatus.locInDatagram,
319 partLenPayload - CHPP_PREAMBLE_LEN_BYTES - sizeof(ChppTransportHeader));
320 EXPECT_EQ(mTransportContext.rxDatagram.length, payloadLen);
321 endAndValidatePacket(&mTransportContext);
322
323 chppWorkThreadStop(&mTransportContext);
324 t1.join();
325 }
326
327 /**
328 * End of Packet Link Notification during footer
329 */
TEST_F(TransportTests,LinkSendDoneFooter)330 TEST_F(TransportTests, LinkSendDoneFooter) {
331 size_t payloadLen = 1000;
332 size_t partLenFooter = CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) +
333 payloadLen + sizeof(ChppTransportFooter) - 1;
334
335 mTransportContext.rxStatus.state = CHPP_STATE_PREAMBLE;
336 std::thread t1(chppWorkThreadStart, &mTransportContext);
337 waitForLinkSendDone();
338
339 size_t loc = 0;
340 addPreambleToBuf(mBuf, &loc);
341 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &loc);
342 transHeader->length = static_cast<uint16_t>(payloadLen);
343 loc += payloadLen;
344 addTransportFooterToBuf(mBuf, &loc);
345
346 EXPECT_FALSE(chppRxDataCb(&mTransportContext, mBuf, partLenFooter));
347 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_FOOTER);
348 EXPECT_EQ(mTransportContext.rxHeader.length, payloadLen);
349 EXPECT_EQ(mTransportContext.rxStatus.locInDatagram, payloadLen);
350 EXPECT_EQ(mTransportContext.rxDatagram.length, payloadLen);
351 endAndValidatePacket(&mTransportContext);
352
353 chppWorkThreadStop(&mTransportContext);
354 t1.join();
355 }
356
TEST_P(TransportTests,EnqueueDatagrams)357 TEST_P(TransportTests, EnqueueDatagrams) {
358 size_t len = static_cast<size_t>(GetParam());
359
360 if (len <= CHPP_TX_DATAGRAM_QUEUE_LEN) {
361 // Add (len) datagrams of various length to queue
362
363 int fr = 0;
364
365 for (int j = 0; j == CHPP_TX_DATAGRAM_QUEUE_LEN; j++) {
366 for (size_t i = 1; i <= len; i++) {
367 uint8_t *mBuf = (uint8_t *)chppMalloc(i + 100);
368 EXPECT_TRUE(
369 chppEnqueueTxDatagramOrFail(&mTransportContext, mBuf, i + 100));
370
371 EXPECT_EQ(mTransportContext.txDatagramQueue.pending, i);
372 EXPECT_EQ(mTransportContext.txDatagramQueue.front, fr);
373 EXPECT_EQ(mTransportContext.txDatagramQueue
374 .datagram[(i - 1 + fr) % CHPP_TX_DATAGRAM_QUEUE_LEN]
375 .length,
376 i + 100);
377 }
378
379 if (mTransportContext.txDatagramQueue.pending ==
380 CHPP_TX_DATAGRAM_QUEUE_LEN) {
381 uint8_t *mBuf = (uint8_t *)chppMalloc(100);
382 EXPECT_FALSE(
383 chppEnqueueTxDatagramOrFail(&mTransportContext, mBuf, 100));
384 CHPP_FREE_AND_NULLIFY(mBuf);
385 }
386
387 for (size_t i = len; i > 0; i--) {
388 fr++;
389 fr %= CHPP_TX_DATAGRAM_QUEUE_LEN;
390
391 EXPECT_TRUE(chppDequeueTxDatagram(&mTransportContext));
392
393 EXPECT_EQ(mTransportContext.txDatagramQueue.front, fr);
394 EXPECT_EQ(mTransportContext.txDatagramQueue.pending, i - 1);
395 }
396
397 EXPECT_FALSE(chppDequeueTxDatagram(&mTransportContext));
398
399 EXPECT_EQ(mTransportContext.txDatagramQueue.front, fr);
400 EXPECT_EQ(mTransportContext.txDatagramQueue.pending, 0);
401 }
402 }
403 }
404
405 /**
406 * Loopback testing with various length payloads of zeros
407 */
TEST_P(TransportTests,LoopbackPayloadOfZeros)408 TEST_P(TransportTests, LoopbackPayloadOfZeros) {
409 mTransportContext.rxStatus.state = CHPP_STATE_PREAMBLE;
410 size_t len = static_cast<size_t>(GetParam());
411
412 std::thread t1(chppWorkThreadStart, &mTransportContext);
413 waitForLinkSendDone();
414 chppWorkThreadStop(&mTransportContext);
415 t1.join();
416
417 if (len > 1 && len <= kMaxChunkSize) {
418 // Loopback App header (only 2 fields required)
419 mBuf[0] = CHPP_HANDLE_LOOPBACK;
420 mBuf[1] = CHPP_MESSAGE_TYPE_CLIENT_REQUEST;
421
422 EXPECT_TRUE(chppDispatchLoopbackClientRequest(&mAppContext, mBuf, len));
423
424 uint16_t end = (mTransportContext.txDatagramQueue.front +
425 mTransportContext.txDatagramQueue.pending - 1) %
426 CHPP_TX_DATAGRAM_QUEUE_LEN;
427
428 EXPECT_EQ(mTransportContext.txDatagramQueue.datagram[end].length, len);
429 EXPECT_EQ(mTransportContext.txDatagramQueue.datagram[end].payload[0],
430 CHPP_HANDLE_LOOPBACK);
431 EXPECT_EQ(mTransportContext.txDatagramQueue.datagram[end].payload[1],
432 CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
433 }
434 }
435
436 /**
437 * Discovery service + Transaction ID
438 */
TEST_P(TransportTests,DiscoveryAndTransactionID)439 TEST_P(TransportTests, DiscoveryAndTransactionID) {
440 uint8_t transactionID = static_cast<uint8_t>(GetParam());
441 size_t len = 0;
442
443 std::thread t1(chppWorkThreadStart, &mTransportContext);
444 waitForLinkSendDone();
445 chppWorkThreadStop(&mTransportContext);
446 t1.join();
447
448 ChppAppHeader *appHeader = addAppHeaderToBuf(mBuf, &len);
449 appHeader->handle = CHPP_HANDLE_DISCOVERY;
450 appHeader->transaction = transactionID;
451 appHeader->command = CHPP_DISCOVERY_COMMAND_DISCOVER_ALL;
452
453 EXPECT_TRUE(chppDispatchDiscoveryClientRequest(&mAppContext, mBuf, len));
454
455 uint16_t end = (mTransportContext.txDatagramQueue.front +
456 mTransportContext.txDatagramQueue.pending - 1) %
457 CHPP_TX_DATAGRAM_QUEUE_LEN;
458
459 struct ChppAppHeader *responseHeader =
460 (ChppAppHeader *)mTransportContext.txDatagramQueue.datagram[end].payload;
461
462 EXPECT_EQ(responseHeader->handle, CHPP_HANDLE_DISCOVERY);
463 EXPECT_EQ(responseHeader->type, CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
464 EXPECT_EQ(responseHeader->transaction, transactionID);
465 EXPECT_EQ(responseHeader->error, CHPP_APP_ERROR_NONE);
466 EXPECT_EQ(responseHeader->command, CHPP_DISCOVERY_COMMAND_DISCOVER_ALL);
467
468 // Decode discovery response
469 ChppServiceDescriptor *services =
470 (ChppServiceDescriptor *)&mTransportContext.txDatagramQueue.datagram[end]
471 .payload[sizeof(ChppAppHeader)];
472
473 // Check total length (and implicit service count)
474 EXPECT_EQ(
475 mTransportContext.txDatagramQueue.datagram[end].length,
476 sizeof(ChppAppHeader) + kServiceCount * sizeof(ChppServiceDescriptor));
477
478 // Check service configuration response
479 ChppServiceDescriptor wwanServiceDescriptor = {};
480 static const uint8_t uuid[CHPP_SERVICE_UUID_LEN] = CHPP_UUID_WWAN_STANDARD;
481 memcpy(&wwanServiceDescriptor.uuid, &uuid,
482 sizeof(wwanServiceDescriptor.uuid));
483 static const char name[CHPP_SERVICE_NAME_MAX_LEN] = "WWAN";
484 memcpy(&wwanServiceDescriptor.name, &name,
485 sizeof(wwanServiceDescriptor.name));
486 wwanServiceDescriptor.version.major = 1;
487 wwanServiceDescriptor.version.minor = 0;
488 wwanServiceDescriptor.version.patch = 0;
489
490 EXPECT_EQ(std::memcmp(services[0].uuid, wwanServiceDescriptor.uuid,
491 sizeof(wwanServiceDescriptor.uuid)),
492 0);
493 EXPECT_EQ(std::memcmp(services[0].name, wwanServiceDescriptor.name,
494 sizeof(wwanServiceDescriptor.name)),
495 0);
496 EXPECT_EQ(services[0].version.major, wwanServiceDescriptor.version.major);
497 EXPECT_EQ(services[0].version.minor, wwanServiceDescriptor.version.minor);
498 EXPECT_EQ(services[0].version.patch, wwanServiceDescriptor.version.patch);
499 }
500
501 /**
502 * CRC-32 calculation for several pre-known test vectors.
503 */
TEST_F(TransportTests,CRC32Basic)504 TEST_F(TransportTests, CRC32Basic) {
505 static const char kTest1Str[] = "Hello World Test!";
506 static const uint8_t *kTest1 = (const uint8_t *)kTest1Str;
507 EXPECT_EQ(chppCrc32(0, kTest1, 17), 0x613B1D74);
508 EXPECT_EQ(chppCrc32(0, kTest1, 16), 0x5F88D7D9);
509 EXPECT_EQ(chppCrc32(0, kTest1, 1), 0xAA05262F);
510 EXPECT_EQ(chppCrc32(0, kTest1, 0), 0x00000000);
511
512 static const uint8_t kTest2[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
513 EXPECT_EQ(chppCrc32(0, kTest2, 6), 0x41D9ED00);
514 EXPECT_EQ(chppCrc32(0, kTest2, 5), 0xD2FD1072);
515 EXPECT_EQ(chppCrc32(0, kTest2, 4), 0xFFFFFFFF);
516 EXPECT_EQ(chppCrc32(0, kTest2, 3), 0xFFFFFF00);
517 EXPECT_EQ(chppCrc32(0, kTest2, 2), 0xFFFF0000);
518 EXPECT_EQ(chppCrc32(0, kTest2, 1), 0xFF000000);
519 EXPECT_EQ(chppCrc32(0, kTest2, 0), 0x00000000);
520
521 static const char kTest3Str[] = "123456789";
522 static const uint8_t *kTest3 = (const uint8_t *)kTest3Str;
523 EXPECT_EQ(chppCrc32(0, kTest3, 9), 0xCBF43926);
524
525 static const uint8_t kTest4[] = {0x00, 0x00, 0x00, 0x00};
526 EXPECT_EQ(chppCrc32(0, kTest4, sizeof(kTest4)), 0x2144DF1C);
527
528 static const uint8_t kTest5[] = {0xF2, 0x01, 0x83};
529 EXPECT_EQ(chppCrc32(0, kTest5, sizeof(kTest5)), 0x24AB9D77);
530
531 static const uint8_t kTest6[] = {0x0F, 0xAA, 0x00, 0x55};
532 EXPECT_EQ(chppCrc32(0, kTest6, sizeof(kTest6)), 0xB6C9B287);
533
534 static const uint8_t kTest7[] = {0x00, 0xFF, 0x55, 0x11};
535 EXPECT_EQ(chppCrc32(0, kTest7, sizeof(kTest7)), 0x32A06212);
536
537 static const uint8_t kTest8[] = {0x33, 0x22, 0x55, 0xAA, 0xBB,
538 0xCC, 0xDD, 0xEE, 0xFF};
539 EXPECT_EQ(chppCrc32(0, kTest8, sizeof(kTest8)), 0xB0AE863D);
540
541 static const uint8_t kTest9[] = {0x92, 0x6B, 0x55};
542 EXPECT_EQ(chppCrc32(0, kTest9, sizeof(kTest9)), 0x9CDEA29B);
543 }
544
545 /**
546 * CRC-32 calculation for daisy-chained input.
547 */
TEST_F(TransportTests,CRC32DaisyChained)548 TEST_F(TransportTests, CRC32DaisyChained) {
549 static const size_t kMaxLen = 10000;
550 uint8_t test[kMaxLen];
551 // Populate test with 8-bit LFSR
552 // Feedback polynomial is x^8 + x^6 + x^5 + x^4 + 1
553 static uint8_t lfsr = 1;
554 for (size_t i = 0; i < kMaxLen; i++) {
555 test[i] = lfsr;
556 lfsr = (lfsr >> 1) |
557 (((lfsr << 7) ^ (lfsr << 5) ^ (lfsr << 4) ^ (lfsr << 3)) & 0x80);
558 }
559
560 for (size_t len = 0; len < kMaxLen; len += 1000) {
561 uint32_t fullCRC = chppCrc32(0, &test[0], len);
562 for (size_t partition = 0; partition <= len; partition++) {
563 uint32_t partialCRC = chppCrc32(0, &test[0], partition);
564 EXPECT_EQ(chppCrc32(partialCRC, &test[partition], len - partition),
565 fullCRC);
566 }
567 }
568 }
569
570 /**
571 * WWAN service Open and GetCapabilities.
572 */
TEST_F(TransportTests,WwanOpen)573 TEST_F(TransportTests, WwanOpen) {
574 std::thread t1(chppWorkThreadStart, &mTransportContext);
575 waitForLinkSendDone();
576
577 uint8_t ackSeq = 1;
578 uint8_t seq = 0;
579 uint8_t handle = CHPP_HANDLE_NEGOTIATED_RANGE_START;
580 uint8_t transactionID = 0;
581 size_t len = 0;
582
583 EXPECT_EQ(findServiceHandle(&mAppContext, "WWAN", &handle), true);
584
585 openService(&mTransportContext, mBuf, ackSeq++, seq++, handle,
586 transactionID++, CHPP_WWAN_OPEN, gChppLinuxLinkContext);
587
588 addPreambleToBuf(mBuf, &len);
589
590 uint16_t command = CHPP_WWAN_GET_CAPABILITIES;
591 sendCommandToService(&mTransportContext, mBuf, ackSeq++, seq++, handle,
592 transactionID++, command, gChppLinuxLinkContext);
593
594 size_t responseLoc = sizeof(ChppTestResponse);
595
596 // Validate capabilities
597 uint32_t *capabilities = (uint32_t *)&gChppLinuxLinkContext.buf[responseLoc];
598 responseLoc += sizeof(uint32_t);
599
600 // Cleanup
601 chppWorkThreadStop(&mTransportContext);
602 t1.join();
603
604 uint32_t capabilitySet = CHRE_WWAN_GET_CELL_INFO;
605 EXPECT_EQ((*capabilities) & ~(capabilitySet), 0);
606
607 // Check total length
608 EXPECT_EQ(responseLoc, CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) +
609 sizeof(ChppWwanGetCapabilitiesResponse));
610 }
611
612 /**
613 * WiFi service Open and GetCapabilities.
614 */
TEST_F(TransportTests,WifiOpen)615 TEST_F(TransportTests, WifiOpen) {
616 std::thread t1(chppWorkThreadStart, &mTransportContext);
617 waitForLinkSendDone();
618
619 uint8_t ackSeq = 1;
620 uint8_t seq = 0;
621 uint8_t handle = CHPP_HANDLE_NEGOTIATED_RANGE_START + 1;
622 uint8_t transactionID = 0;
623
624 EXPECT_EQ(findServiceHandle(&mAppContext, "WiFi", &handle), true);
625
626 openService(&mTransportContext, mBuf, ackSeq++, seq++, handle,
627 transactionID++, CHPP_WIFI_OPEN, gChppLinuxLinkContext);
628
629 uint16_t command = CHPP_WIFI_GET_CAPABILITIES;
630 sendCommandToService(&mTransportContext, mBuf, ackSeq++, seq++, handle,
631 transactionID++, command, gChppLinuxLinkContext);
632
633 size_t responseLoc = sizeof(ChppTestResponse);
634
635 // Cleanup
636 chppWorkThreadStop(&mTransportContext);
637 t1.join();
638
639 // Validate capabilities
640 uint32_t *capabilities = (uint32_t *)&gChppLinuxLinkContext.buf[responseLoc];
641 responseLoc += sizeof(uint32_t);
642
643 uint32_t capabilitySet = CHRE_WIFI_CAPABILITIES_SCAN_MONITORING |
644 CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN |
645 CHRE_WIFI_CAPABILITIES_RADIO_CHAIN_PREF |
646 CHRE_WIFI_CAPABILITIES_RTT_RANGING |
647 CHRE_WIFI_CAPABILITIES_NAN_SUB;
648 EXPECT_EQ((*capabilities) & ~(capabilitySet), 0);
649
650 // Check total length
651 EXPECT_EQ(responseLoc, CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) +
652 sizeof(ChppWwanGetCapabilitiesResponse));
653 }
654
655 /**
656 * GNSS service Open and GetCapabilities.
657 */
TEST_F(TransportTests,GnssOpen)658 TEST_F(TransportTests, GnssOpen) {
659 std::thread t1(chppWorkThreadStart, &mTransportContext);
660 waitForLinkSendDone();
661
662 uint8_t ackSeq = 1;
663 uint8_t seq = 0;
664 uint8_t handle = CHPP_HANDLE_NEGOTIATED_RANGE_START + 2;
665 uint8_t transactionID = 0;
666 size_t len = 0;
667
668 EXPECT_EQ(findServiceHandle(&mAppContext, "GNSS", &handle), true);
669
670 openService(&mTransportContext, mBuf, ackSeq++, seq++, handle,
671 transactionID++, CHPP_GNSS_OPEN, gChppLinuxLinkContext);
672
673 addPreambleToBuf(mBuf, &len);
674
675 uint16_t command = CHPP_GNSS_GET_CAPABILITIES;
676 sendCommandToService(&mTransportContext, mBuf, ackSeq++, seq++, handle,
677 transactionID++, command, gChppLinuxLinkContext);
678
679 size_t responseLoc = sizeof(ChppTestResponse);
680
681 // Cleanup
682 chppWorkThreadStop(&mTransportContext);
683 t1.join();
684
685 // Validate capabilities
686 uint32_t *capabilities = (uint32_t *)&gChppLinuxLinkContext.buf[responseLoc];
687 responseLoc += sizeof(uint32_t);
688
689 uint32_t capabilitySet =
690 CHRE_GNSS_CAPABILITIES_LOCATION | CHRE_GNSS_CAPABILITIES_MEASUREMENTS |
691 CHRE_GNSS_CAPABILITIES_GNSS_ENGINE_BASED_PASSIVE_LISTENER;
692 EXPECT_EQ((*capabilities) & ~(capabilitySet), 0);
693
694 // Check total length
695 EXPECT_EQ(responseLoc, CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) +
696 sizeof(ChppGnssGetCapabilitiesResponse));
697 }
698
699 /**
700 * Discovery client.
701 */
TEST_F(TransportTests,Discovery)702 TEST_F(TransportTests, Discovery) {
703 size_t len = 0;
704
705 std::thread t1(chppWorkThreadStart, &mTransportContext);
706 waitForLinkSendDone();
707
708 addPreambleToBuf(mBuf, &len);
709
710 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &len);
711
712 ChppAppHeader *appHeader = addAppHeaderToBuf(mBuf, &len);
713 appHeader->handle = CHPP_HANDLE_DISCOVERY;
714 appHeader->command = CHPP_DISCOVERY_COMMAND_DISCOVER_ALL;
715 appHeader->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
716
717 ChppServiceDescriptor wwanServiceDescriptor = {};
718 static const uint8_t uuid[CHPP_SERVICE_UUID_LEN] = CHPP_UUID_WWAN_STANDARD;
719 memcpy(&wwanServiceDescriptor.uuid, &uuid,
720 sizeof(wwanServiceDescriptor.uuid));
721 static const char name[CHPP_SERVICE_NAME_MAX_LEN] = "WWAN";
722 memcpy(&wwanServiceDescriptor.name, &name,
723 sizeof(wwanServiceDescriptor.name));
724 wwanServiceDescriptor.version.major = 1;
725 wwanServiceDescriptor.version.minor = 0;
726 wwanServiceDescriptor.version.patch = 0;
727
728 memcpy(&mBuf[len], &wwanServiceDescriptor, sizeof(ChppServiceDescriptor));
729 len += sizeof(ChppServiceDescriptor);
730
731 transHeader->length = static_cast<uint16_t>(
732 len - sizeof(ChppTransportHeader) - CHPP_PREAMBLE_LEN_BYTES);
733
734 addTransportFooterToBuf(mBuf, &len);
735
736 // Initialize clientIndexOfServiceIndex[0] to see if it correctly updated
737 // upon discovery
738 mAppContext.clientIndexOfServiceIndex[0] = CHPP_CLIENT_INDEX_NONE;
739
740 // Send header + payload (if any) + footer
741 EXPECT_TRUE(chppRxDataCb(&mTransportContext, mBuf, len));
742
743 // Cleanup
744 chppWorkThreadStop(&mTransportContext);
745 t1.join();
746
747 // Check for correct state
748 EXPECT_EQ(mAppContext.clientIndexOfServiceIndex[0], 0);
749 uint8_t nextSeq = transHeader->seq + 1;
750 EXPECT_EQ(mTransportContext.rxStatus.expectedSeq, nextSeq);
751 EXPECT_EQ(mTransportContext.rxStatus.state, CHPP_STATE_PREAMBLE);
752 }
753
754 /**
755 * Unopened clients should not crash upon an unsolicitated service response.
756 */
TEST_F(TransportTests,UnopenedClient)757 TEST_F(TransportTests, UnopenedClient) {
758 size_t len = 0;
759 uint8_t *buf = (uint8_t *)chppMalloc(100);
760
761 std::thread t1(chppWorkThreadStart, &mTransportContext);
762 waitForLinkSendDone();
763 chppWorkThreadStop(&mTransportContext);
764 t1.join();
765
766 ChppAppHeader *appHeader = addAppHeaderToBuf(buf, &len);
767 appHeader->handle = CHPP_HANDLE_NEGOTIATED_RANGE_START + 1;
768 appHeader->command = CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC;
769 appHeader->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
770 len = sizeof(struct ChppWifiConfigureScanMonitorAsyncResponse);
771
772 ASSERT_EQ(mAppContext.registeredServiceCount, kServiceCount);
773
774 chppAppProcessRxDatagram(&mAppContext, buf, len);
775
776 EXPECT_EQ(mTransportContext.txStatus.packetCodeToSend,
777 CHPP_TRANSPORT_ERROR_APPLAYER);
778 }
779
TEST_F(TransportTests,DiscardedPacketTest)780 TEST_F(TransportTests, DiscardedPacketTest) {
781 std::thread t1(chppWorkThreadStart, &mTransportContext);
782 waitForLinkSendDone();
783
784 // Send packet to RX thread after manually setting to resetting state.
785 // We expect this packet to get dropped, but this test checks for any
786 // problematic behavior (e.g. memory leaks).
787 mTransportContext.resetState = CHPP_RESET_STATE_RESETTING;
788
789 size_t loc = 0;
790 addPreambleToBuf(mBuf, &loc);
791 ChppTransportHeader *transHeader = addTransportHeaderToBuf(mBuf, &loc);
792
793 ChppAppHeader *appHeader = addAppHeaderToBuf(mBuf, &loc);
794 appHeader->handle = CHPP_HANDLE_DISCOVERY;
795 appHeader->command = CHPP_DISCOVERY_COMMAND_DISCOVER_ALL;
796 appHeader->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
797
798 ChppServiceDescriptor wwanServiceDescriptor = {};
799 static const uint8_t uuid[CHPP_SERVICE_UUID_LEN] = CHPP_UUID_WWAN_STANDARD;
800 memcpy(&wwanServiceDescriptor.uuid, &uuid,
801 sizeof(wwanServiceDescriptor.uuid));
802 static const char name[CHPP_SERVICE_NAME_MAX_LEN] = "WWAN";
803 memcpy(&wwanServiceDescriptor.name, &name,
804 sizeof(wwanServiceDescriptor.name));
805 wwanServiceDescriptor.version.major = 1;
806 wwanServiceDescriptor.version.minor = 0;
807 wwanServiceDescriptor.version.patch = 0;
808
809 memcpy(&mBuf[loc], &wwanServiceDescriptor, sizeof(ChppServiceDescriptor));
810 loc += sizeof(ChppServiceDescriptor);
811
812 transHeader->length = static_cast<uint16_t>(
813 loc - sizeof(ChppTransportHeader) - CHPP_PREAMBLE_LEN_BYTES);
814
815 addTransportFooterToBuf(mBuf, &loc);
816
817 mAppContext.clientIndexOfServiceIndex[0] = CHPP_CLIENT_INDEX_NONE;
818
819 EXPECT_TRUE(chppRxDataCb(&mTransportContext, mBuf, loc));
820
821 chppWorkThreadStop(&mTransportContext);
822 t1.join();
823 }
824
825 /*
826 * Correctly handle messages directed to clients / services with an invalid
827 * handle number.
828 */
messageToInvalidHandle(ChppTransportState * transportContext,uint8_t type)829 void messageToInvalidHandle(ChppTransportState *transportContext,
830 uint8_t type) {
831 size_t len = 0;
832 uint8_t *buf = (uint8_t *)chppMalloc(100);
833
834 std::thread t1(chppWorkThreadStart, transportContext);
835 waitForLinkSendDone();
836 chppWorkThreadStop(transportContext);
837 t1.join();
838
839 ChppAppHeader *appHeader = addAppHeaderToBuf(buf, &len);
840 appHeader->handle =
841 CHPP_HANDLE_NEGOTIATED_RANGE_START +
842 MAX(CHPP_MAX_REGISTERED_CLIENTS, CHPP_MAX_REGISTERED_SERVICES);
843 appHeader->type = type;
844 len = sizeof(struct ChppAppHeader);
845
846 chppAppProcessRxDatagram(transportContext->appContext, buf, len);
847
848 EXPECT_EQ(transportContext->txStatus.packetCodeToSend,
849 CHPP_TRANSPORT_ERROR_APPLAYER);
850 }
851
TEST_F(TransportTests,RequestToInvalidService)852 TEST_F(TransportTests, RequestToInvalidService) {
853 messageToInvalidHandle(&mTransportContext, CHPP_MESSAGE_TYPE_CLIENT_REQUEST);
854 }
855
TEST_F(TransportTests,ResponseToInvalidClient)856 TEST_F(TransportTests, ResponseToInvalidClient) {
857 messageToInvalidHandle(&mTransportContext,
858 CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
859 }
860
TEST_F(TransportTests,NotificationToInvalidService)861 TEST_F(TransportTests, NotificationToInvalidService) {
862 messageToInvalidHandle(&mTransportContext,
863 CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION);
864 }
865
TEST_F(TransportTests,NotificationToInvalidClient)866 TEST_F(TransportTests, NotificationToInvalidClient) {
867 messageToInvalidHandle(&mTransportContext,
868 CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION);
869 }
870
TEST_F(TransportTests,WorkMonitorInvoked)871 TEST_F(TransportTests, WorkMonitorInvoked) {
872 // Send message to spin work thread so it interacts with the work monitor
873 messageToInvalidHandle(&mTransportContext,
874 CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION);
875
876 // 1 pre/post call for executing the work and 1 for shutting down the thread.
877 EXPECT_EQ(mTransportContext.workMonitor.numPreProcessCalls, 2);
878 EXPECT_EQ(mTransportContext.workMonitor.numPostProcessCalls, 2);
879 }
880
881 INSTANTIATE_TEST_SUITE_P(TransportTestRange, TransportTests,
882 testing::ValuesIn(kChunkSizes));
883
884 } // namespace chpp::test
885