• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <gtest/gtest.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include "chpp/transport.h"
22 #include "transport_test.h"
23 
24 namespace {
25 
26 // Max size of payload sent to chppRxDataCb (bytes)
27 constexpr size_t kMaxChunkSize = 20000;
28 
29 constexpr size_t kMaxPacketSize = kMaxChunkSize + CHPP_PREAMBLE_LEN_BYTES +
30                                   sizeof(ChppTransportHeader) +
31                                   sizeof(ChppTransportFooter);
32 
33 // Input sizes to test the entire range of sizes with a few tests
34 constexpr int kChunkSizes[] = {0,  1,   2,   3,    4,     5,    6,
35                                7,  8,   10,  16,   20,    30,   40,
36                                51, 100, 201, 1000, 10001, 20000};
37 
38 /**
39  * Adds a CHPP preamble to the specified location of buf
40  *
41  * @param buf The CHPP preamble will be added to buf
42  * @param loc Location of buf where the CHPP preamble will be added
43  */
chppAddPreamble(uint8_t * buf,size_t loc)44 void chppAddPreamble(uint8_t *buf, size_t loc) {
45   for (size_t i = 0; i < CHPP_PREAMBLE_LEN_BYTES; i++) {
46     buf[loc + i] = static_cast<uint8_t>(
47         CHPP_PREAMBLE_DATA >> (CHPP_PREAMBLE_LEN_BYTES - 1 - i) & 0xff);
48   }
49 }
50 
51 /*
52  * Test suite for the CHPP Transport Layer
53  */
54 class TransportTests : public testing::TestWithParam<int> {
55  protected:
SetUp()56   void SetUp() override {
57     chppTransportInit(&context);
58   }
59 
60   ChppTransportState context = {};
61   uint8_t buf[kMaxPacketSize] = {};
62 };
63 
64 /**
65  * A series of zeros shouldn't change state from CHPP_STATE_PREAMBLE
66  */
TEST_P(TransportTests,ZeroNoPreambleInput)67 TEST_P(TransportTests, ZeroNoPreambleInput) {
68   size_t len = static_cast<size_t>(GetParam());
69   if (len <= kMaxChunkSize) {
70     EXPECT_TRUE(chppRxDataCb(&context, buf, len));
71     EXPECT_EQ(context.rxStatus.state, CHPP_STATE_PREAMBLE);
72   }
73 }
74 
75 /**
76  * A preamble after a series of zeros input should change state from
77  * CHPP_STATE_PREAMBLE to CHPP_STATE_HEADER
78  */
TEST_P(TransportTests,ZeroThenPreambleInput)79 TEST_P(TransportTests, ZeroThenPreambleInput) {
80   size_t len = static_cast<size_t>(GetParam());
81 
82   if (len <= kMaxChunkSize) {
83     // Add preamble at the end of buf
84     chppAddPreamble(buf, MAX(0, len - CHPP_PREAMBLE_LEN_BYTES));
85 
86     if (len >= CHPP_PREAMBLE_LEN_BYTES) {
87       EXPECT_FALSE(chppRxDataCb(&context, buf, len));
88       EXPECT_EQ(context.rxStatus.state, CHPP_STATE_HEADER);
89     } else {
90       EXPECT_TRUE(chppRxDataCb(&context, buf, len));
91       EXPECT_EQ(context.rxStatus.state, CHPP_STATE_PREAMBLE);
92     }
93   }
94 }
95 
96 /**
97  * Rx Testing with various length payloads of zeros
98  */
TEST_P(TransportTests,RxPayloadOfZeros)99 TEST_P(TransportTests, RxPayloadOfZeros) {
100   context.rxStatus.state = CHPP_STATE_HEADER;
101   size_t len = static_cast<size_t>(GetParam());
102 
103   if (len <= kMaxChunkSize) {
104     ChppTransportHeader header{};
105     header.flags = 0;
106     header.errorCode = 0;
107     header.ackSeq = 1;
108     header.seq = 0;
109     header.length = len;
110 
111     memcpy(buf, &header, sizeof(header));
112 
113     // Send header and check for correct state
114     EXPECT_FALSE(chppRxDataCb(&context, buf, sizeof(ChppTransportHeader)));
115     if (len > 0) {
116       EXPECT_EQ(context.rxStatus.state, CHPP_STATE_PAYLOAD);
117     } else {
118       EXPECT_EQ(context.rxStatus.state, CHPP_STATE_FOOTER);
119     }
120 
121     // Correct decoding of packet length
122     EXPECT_EQ(context.rxHeader.length, len);
123     EXPECT_EQ(context.rxStatus.locInDatagram, 0);
124     EXPECT_EQ(context.rxDatagram.length, len);
125 
126     // Send payload if any and check for correct state
127     if (len > 0) {
128       EXPECT_FALSE(
129           chppRxDataCb(&context, &buf[sizeof(ChppTransportHeader)], len));
130       EXPECT_EQ(context.rxStatus.state, CHPP_STATE_FOOTER);
131     }
132 
133     // Should have complete packet payload by now
134     EXPECT_EQ(context.rxStatus.locInDatagram, len);
135 
136     // But no ACK yet
137     EXPECT_FALSE(context.txStatus.hasPacketsToSend);
138     EXPECT_EQ(context.txStatus.errorCodeToSend, CHPP_ERROR_NONE);
139     EXPECT_EQ(context.rxStatus.expectedSeq, header.seq);
140 
141     // Send footer and check for correct state
142     EXPECT_TRUE(chppRxDataCb(&context, &buf[sizeof(ChppTransportHeader) + len],
143                              sizeof(ChppTransportFooter)));
144     EXPECT_EQ(context.rxStatus.state, CHPP_STATE_PREAMBLE);
145 
146     // Should have reset loc and length for next packet / datagram
147     EXPECT_EQ(context.rxStatus.locInDatagram, 0);
148     EXPECT_EQ(context.rxDatagram.length, 0);
149 
150     // If payload packet, expect next packet with incremented sequence #
151     // Otherwise, should keep previous sequence #
152     uint8_t nextSeq = header.seq + ((len > 0) ? 1 : 0);
153     EXPECT_EQ(context.rxStatus.expectedSeq, nextSeq);
154 
155     // Check for correct ACK crafting if applicable
156     // TODO: This will need updating once signalling goes in
157     if (len > 0) {
158       EXPECT_TRUE(context.txStatus.hasPacketsToSend);
159       EXPECT_EQ(context.txStatus.errorCodeToSend, CHPP_ERROR_NONE);
160       EXPECT_EQ(context.txDatagramQueue.pending, 0);
161 
162       chppTransportDoWork(&context);
163 
164       struct ChppTransportHeader *txHeader =
165           (struct ChppTransportHeader *)&context.packetToSend
166               .payload[CHPP_PREAMBLE_LEN_BYTES];
167 
168       EXPECT_EQ(txHeader->flags, CHPP_TRANSPORT_FLAG_FINISHED_DATAGRAM);
169       EXPECT_EQ(txHeader->errorCode, CHPP_ERROR_NONE);
170       EXPECT_EQ(txHeader->ackSeq, nextSeq);
171       EXPECT_EQ(txHeader->length, 0);
172 
173       EXPECT_EQ(context.packetToSend.length,
174                 CHPP_PREAMBLE_LEN_BYTES + sizeof(struct ChppTransportHeader) +
175                     sizeof(struct ChppTransportFooter));
176     }
177   }
178 }
179 
TEST_P(TransportTests,EnqueueDatagrams)180 TEST_P(TransportTests, EnqueueDatagrams) {
181   size_t len = static_cast<size_t>(GetParam());
182 
183   if (len <= CHPP_TX_DATAGRAM_QUEUE_LEN) {
184     // Add (len) datagrams of various length to queue
185 
186     int fr = 0;
187 
188     for (int j = 0; j == CHPP_TX_DATAGRAM_QUEUE_LEN; j++) {
189       for (size_t i = 1; i <= len; i++) {
190         uint8_t *buf = (uint8_t *)chppMalloc(i + 100);
191         EXPECT_TRUE(chppEnqueueTxDatagram(&context, i + 100, buf));
192 
193         EXPECT_EQ(context.txDatagramQueue.pending, i);
194         EXPECT_EQ(context.txDatagramQueue.front, fr);
195         EXPECT_EQ(context.txDatagramQueue
196                       .datagram[(i - 1 + fr) % CHPP_TX_DATAGRAM_QUEUE_LEN]
197                       .length,
198                   i + 100);
199       }
200 
201       if (context.txDatagramQueue.pending == CHPP_TX_DATAGRAM_QUEUE_LEN) {
202         uint8_t *buf = (uint8_t *)chppMalloc(100);
203         EXPECT_FALSE(chppEnqueueTxDatagram(&context, 100, buf));
204         chppFree(buf);
205       }
206 
207       for (size_t i = len; i > 0; i--) {
208         fr++;
209         fr %= CHPP_TX_DATAGRAM_QUEUE_LEN;
210 
211         EXPECT_TRUE(chppDequeueTxDatagram(&context));
212 
213         EXPECT_EQ(context.txDatagramQueue.front, fr);
214         EXPECT_EQ(context.txDatagramQueue.pending, i - 1);
215       }
216 
217       EXPECT_FALSE(chppDequeueTxDatagram(&context));
218 
219       EXPECT_EQ(context.txDatagramQueue.front, fr);
220       EXPECT_EQ(context.txDatagramQueue.pending, 0);
221     }
222   }
223 }
224 
225 INSTANTIATE_TEST_SUITE_P(TransportTestRange, TransportTests,
226                          testing::ValuesIn(kChunkSizes));
227 
228 }  // namespace
229