1 /*
2  * Copyright 2019, 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 "remote_connection.h"
18 
19 #include "hwsim.h"
20 #include "frame.h"
21 #include "log.h"
22 
23 #include <errno.h>
24 #include <linux/kernel.h>
25 #include <netinet/in.h>
26 #include <qemu_pipe_bp.h>
27 #include <sys/uio.h>
28 #include <unistd.h>
29 
30 static const char kQemuPipeName[] = "qemud:wififorward";
31 static const size_t kReceiveBufferIncrement = 32768;
32 static const size_t kReceiveBufferMaxSize = 1 << 20;
33 
34 static const uint8_t kWifiForwardVersion = 0x01;
35 static const uint32_t kWifiForwardMagic = 0xD6C4B3A2;
36 
37 // This matches with the kernel constant IEEE80211_TX_MAX_RATES in
38 // include/net/mac80211.h in the kernel tree.
39 static const uint32_t kMaxNumRates = 4;
40 
41 struct WifiForwardHeader {
WifiForwardHeaderWifiForwardHeader42     WifiForwardHeader(FrameType type, const MacAddress& transmitter,
43                       uint32_t fullLength, uint64_t cookie,
44                       uint32_t flags, uint32_t channel, uint32_t numRates,
45                       const hwsim_tx_rate* txRates)
46         : magic(__cpu_to_le32(kWifiForwardMagic))
47         , version(kWifiForwardVersion)
48         , type(static_cast<uint16_t>(type))
49         , transmitter(transmitter)
50         , dataOffset(sizeof(WifiForwardHeader))
51         , fullLength(__cpu_to_le32(fullLength))
52         , cookie(__cpu_to_le64(cookie))
53         , flags(__cpu_to_le32(flags))
54         , channel(__cpu_to_le32(channel))
55         , numRates(__cpu_to_le32(numRates)) {
56             memcpy(rates, txRates, std::min(numRates, kMaxNumRates));
57             if (numRates < kMaxNumRates) {
58                 memset(&rates[numRates],
59                        0,
60                        sizeof(rates[0]) * (kMaxNumRates - numRates));
61             }
62         }
63 
64     uint32_t magic;
65     uint8_t version;
66     uint8_t type;
67     MacAddress transmitter;
68     uint16_t dataOffset;
69     uint32_t fullLength;
70     uint64_t cookie;
71     uint32_t flags;
72     uint32_t channel;
73     uint32_t numRates;
74     hwsim_tx_rate rates[kMaxNumRates];
75 } __attribute__((__packed__));
76 
RemoteConnection(OnFrameCallback onFrameCallback,OnAckCallback onAckCallback,OnErrorCallback onErrorCallback)77 RemoteConnection::RemoteConnection(OnFrameCallback onFrameCallback,
78                                    OnAckCallback onAckCallback,
79                                    OnErrorCallback onErrorCallback)
80     : mOnFrameCallback(onFrameCallback)
81     , mOnAckCallback(onAckCallback)
82     , mOnErrorCallback(onErrorCallback) {
83 
84 }
85 
~RemoteConnection()86 RemoteConnection::~RemoteConnection() {
87     if (mPipeFd != -1) {
88         ::close(mPipeFd);
89         mPipeFd = -1;
90     }
91 }
92 
init()93 Result RemoteConnection::init() {
94     if (mPipeFd != -1) {
95         return Result::error("RemoteConnetion already initialized");
96     }
97 
98     mPipeFd = qemu_pipe_open_ns(NULL, kQemuPipeName, O_RDWR);
99     if (mPipeFd == -1) {
100         return Result::error("RemoteConnection failed to open pipe");
101     }
102     return Result::success();
103 }
104 
getTimeout() const105 Pollable::Timestamp RemoteConnection::getTimeout() const {
106     // If there is no pipe return the deadline, we're going to retry, otherwise
107     // use an infinite timeout.
108     return mPipeFd == -1 ? mDeadline : Pollable::Timestamp::max();
109 }
110 
receive()111 void RemoteConnection::receive() {
112     size_t start = mBuffer.size();
113     size_t newSize = start + kReceiveBufferIncrement;
114     if (newSize > kReceiveBufferMaxSize) {
115         // We've exceeded the maximum allowed size, drop everything we have so
116         // far and start over. This is most likely caused by some delay in
117         // injection or the injection failing in which case keeping old data
118         // around isn't going to be very useful.
119         ALOGE("RemoteConnection ran out of buffer space");
120         newSize = kReceiveBufferIncrement;
121         start = 0;
122     }
123     mBuffer.resize(newSize);
124 
125     while (true) {
126         int result = ::read(mPipeFd,
127                             mBuffer.data() + start,
128                             mBuffer.size() - start);
129         if (result < 0) {
130             if (errno == EINTR) {
131                 continue;
132             }
133             ALOGE("RemoteConnection failed to read to forward buffer: %s",
134                  strerror(errno));
135             // Return the buffer to its previous size
136             mBuffer.resize(start);
137             return;
138         } else if (result == 0) {
139             // Nothing received, nothing to write
140             // Return the buffer to its previous size
141             mBuffer.resize(start);
142             ALOGE("RemoteConnection did not receive anything to inject");
143             return;
144         }
145         // Adjust the buffer size to match everything we recieved
146         mBuffer.resize(start + static_cast<size_t>(result));
147         break;
148     }
149 
150     while (mBuffer.size() >= sizeof(WifiForwardHeader)) {
151         auto fwd = reinterpret_cast<WifiForwardHeader*>(mBuffer.data());
152         if (__le32_to_cpu(fwd->magic) != kWifiForwardMagic) {
153             // We are not properly aligned, this can happen for the first read
154             // if the client or server happens to send something that's in the
155             // middle of a stream. Attempt to find the next packet boundary.
156             ALOGE("RemoteConnection found incorrect magic, finding next magic");
157             uint32_t le32magic = __cpu_to_le32(kWifiForwardMagic);
158             auto next = reinterpret_cast<unsigned char*>(
159                     ::memmem(mBuffer.data(), mBuffer.size(),
160                              &le32magic, sizeof(le32magic)));
161             if (next) {
162                 // We've found a possible candidate, erase everything before
163                 size_t length = next - mBuffer.data();
164                 mBuffer.erase(mBuffer.begin(), mBuffer.begin() + length);
165                 continue;
166             } else {
167                 // There is no possible candidate, drop everything except the
168                 // last three bytes. The last three bytes could possibly be the
169                 // start of the next magic without actually triggering the
170                 // search above.
171                 if (mBuffer.size() > 3) {
172                     mBuffer.erase(mBuffer.begin(), mBuffer.end() - 3);
173                 }
174                 // In this case there is nothing left to parse so just return
175                 // right away.
176                 return;
177             }
178         }
179         // Check if we support this version
180         if (fwd->version != kWifiForwardVersion) {
181             // Unsupported version
182             if (!mReportedVersionMismatches.test(fwd->version)) {
183                 // Only report these once per version or this might become
184                 // very spammy.
185                 ALOGE("RemoteConnection encountered unknown version %u",
186                      fwd->version);
187                 mReportedVersionMismatches.set(fwd->version);
188             }
189             // Drop the magic from the buffer and attempt to find the next magic
190             mBuffer.erase(mBuffer.begin(), mBuffer.begin() + 4);
191             continue;
192         }
193         // The length according to the wifi forward header
194         const uint32_t fullLength = __le32_to_cpu(fwd->fullLength);
195         const uint16_t offset = __le16_to_cpu(fwd->dataOffset);
196         if (offset < sizeof(WifiForwardHeader) || offset > fullLength) {
197             // The frame offset is not large enough to go past the header
198             // or it's outside of the bounds of the length of the frame.
199             ALOGE("Invalid data offset in header %u, full length is %u",
200                  offset, fullLength);
201             // Erase the magic and try again
202             mBuffer.erase(mBuffer.begin(), mBuffer.begin() + 4);
203             continue;
204         }
205         const size_t frameLength = fullLength - offset;
206 
207         if (fullLength > mBuffer.size()) {
208             // We have not received enough data yet, wait for more to arrive.
209             return;
210         }
211 
212         FrameType type = frameTypeFromByte(fwd->type);
213         if (frameLength == 0 && type != FrameType::Ack) {
214             ALOGE("Received empty frame for non-ack frame");
215             return;
216         }
217         unsigned char* frameData = mBuffer.data() + offset;
218         if (type == FrameType::Ack) {
219             FrameInfo info(fwd->transmitter,
220                            __le64_to_cpu(fwd->cookie),
221                            __le32_to_cpu(fwd->flags),
222                            __le32_to_cpu(fwd->channel),
223                            fwd->rates,
224                            __le32_to_cpu(fwd->numRates));
225 
226             if (info.flags() & HWSIM_TX_STAT_ACK) {
227                 mOnAckCallback(info);
228             } else {
229                 mOnErrorCallback(info);
230             }
231         } else if (type == FrameType::Data) {
232             auto frame = std::make_unique<Frame>(frameData,
233                                                  frameLength,
234                                                  fwd->transmitter,
235                                                  __le64_to_cpu(fwd->cookie),
236                                                  __le32_to_cpu(fwd->flags),
237                                                  __le32_to_cpu(fwd->channel),
238                                                  fwd->rates,
239                                                  __le32_to_cpu(fwd->numRates));
240             mOnFrameCallback(std::move(frame));
241         } else {
242             ALOGE("Received unknown message type %u from remote",
243                  static_cast<uint8_t>(fwd->type));
244         }
245 
246         mBuffer.erase(mBuffer.begin(), mBuffer.begin() + fullLength);
247     }
248 }
249 
sendFrame(std::unique_ptr<Frame> frame)250 bool RemoteConnection::sendFrame(std::unique_ptr<Frame> frame) {
251     if (mPipeFd == -1) {
252         ALOGE("RemoteConnection unable to forward data, pipe not open");
253         return false;
254     }
255 
256     WifiForwardHeader header(FrameType::Data,
257                              frame->transmitter(),
258                              frame->size() + sizeof(WifiForwardHeader),
259                              frame->cookie(),
260                              frame->flags(),
261                              frame->channel(),
262                              frame->rates().size(),
263                              frame->rates().data());
264 #if 1
265     constexpr size_t count = 2;
266     struct iovec iov[count];
267     iov[0].iov_base = &header;
268     iov[0].iov_len = sizeof(header);
269     iov[1].iov_base = frame->data();
270     iov[1].iov_len = frame->size();
271 
272     size_t totalSize = iov[0].iov_len + iov[1].iov_len;
273 
274     size_t current = 0;
275     for (;;) {
276         ssize_t written = ::writev(mPipeFd, iov + current, count - current);
277         if (written < 0) {
278             ALOGE("RemoteConnection failed to write to pipe: %s",
279                   strerror(errno));
280             return false;
281         }
282         if (static_cast<size_t>(written) == totalSize) {
283             // Optimize for most common case, everything was written
284             break;
285         }
286         totalSize -= written;
287         // Determine how much is left to write after this
288         while (current < count && written >= iov[current].iov_len) {
289             written -= iov[current++].iov_len;
290         }
291         if (current == count) {
292             break;
293         }
294         iov[current].iov_base =
295             reinterpret_cast<char*>(iov[current].iov_base) + written;
296         iov[current].iov_len -= written;
297     }
298 #else
299     if (qemu_pipe_write_fully(mPipeFd, &header, sizeof(header))) {
300         ALOGE("RemoteConnection failed to write to pipe: %s", strerror(errno));
301         return false;
302     }
303 
304     if (qemu_pipe_write_fully(mPipeFd, frame->data(), frame->size())) {
305         ALOGE("RemoteConnection failed to write to pipe: %s", strerror(errno));
306         return false;
307     }
308 #endif
309     return true;
310 }
311 
ackFrame(FrameInfo & info,bool success)312 bool RemoteConnection::ackFrame(FrameInfo& info, bool success) {
313     uint32_t flags = info.flags();
314     if (success) {
315         flags |= HWSIM_TX_STAT_ACK;
316     }
317     WifiForwardHeader header(FrameType::Ack,
318                              info.transmitter(),
319                              sizeof(WifiForwardHeader),
320                              info.cookie(),
321                              flags,
322                              info.channel(),
323                              info.rates().size(),
324                              info.rates().data());
325 
326     if (qemu_pipe_write_fully(mPipeFd, &header, sizeof(header))) {
327         ALOGE("RemoteConnection failed to write to pipe: %s", strerror(errno));
328         return false;
329     }
330     return true;
331 }
332