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