1 /*
2 * Copyright 2018, 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 "wifi_forwarder.h"
18
19 #include "log.h"
20
21 #include <inttypes.h>
22 #include <arpa/inet.h>
23 #include <errno.h>
24 #include <linux/if_packet.h>
25 #include <linux/kernel.h>
26 #include <qemu_pipe_bp.h>
27 #include <string.h>
28 #include <net/ethernet.h>
29 #include <net/if.h>
30 #include <pcap/pcap.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 static const char kQemuPipeName[] = "qemud:wififorward";
36
37 // The largest packet size to capture with pcap on the monitor interface
38 static const int kPcapSnapLength = 65536;
39
40 static const size_t kForwardBufferIncrement = 32768;
41 static const size_t kForwardBufferMaxSize = 1 << 20;
42
43 static const uint32_t kWifiForwardMagic = 0xD5C4B3A2;
44
45 struct WifiForwardHeader {
WifiForwardHeaderWifiForwardHeader46 WifiForwardHeader(uint32_t dataLength, uint32_t radioLength)
47 : magic(__cpu_to_le32(kWifiForwardMagic))
48 , fullLength(__cpu_to_le32(dataLength + sizeof(WifiForwardHeader)))
49 , radioLength(__cpu_to_le32(radioLength)) { }
50
51 uint32_t magic;
52 uint32_t fullLength;
53 uint32_t radioLength;
54 } __attribute__((__packed__));
55
56 struct RadioTapHeader {
57 uint8_t it_version;
58 uint8_t it_pad;
59 uint16_t it_len;
60 uint32_t it_present;
61 } __attribute__((__packed__));
62
63 enum class FrameType {
64 Management,
65 Control,
66 Data,
67 Extension
68 };
69
70 enum class ManagementType {
71 AssociationRequest,
72 AssociationResponse,
73 ReassociationRequest,
74 ReassociationResponse,
75 ProbeRequest,
76 ProbeResponse,
77 TimingAdvertisement,
78 Beacon,
79 Atim,
80 Disassociation,
81 Authentication,
82 Deauthentication,
83 Action,
84 ActionNoAck,
85 };
86
87 enum class ControlType {
88 BeamFormingReportPoll,
89 VhtNdpAnnouncement,
90 ControlFrameExtension,
91 ControlWrapper,
92 BlockAckReq,
93 BlockAck,
94 PsPoll,
95 Rts,
96 Cts,
97 Ack,
98 CfEnd,
99 CfEndCfAck
100 };
101
102 // Since the IEEE 802.11 header can vary in size depending on content we have
103 // to establish a minimum size that we need to be able to inspect and forward
104 // the frame. Every frame need to contain at least frame_control, duration_id,
105 // and addr1.
106 static const uint32_t kMinimumIeee80211Size = sizeof(uint16_t) +
107 sizeof(uint16_t) +
108 sizeof(MacAddress);
109
WifiForwarder(const char * monitorInterfaceName)110 WifiForwarder::WifiForwarder(const char* monitorInterfaceName)
111 : mInterfaceName(monitorInterfaceName),
112 mDeadline(Pollable::Timestamp::max()),
113 mMonitorPcap(nullptr),
114 mPipeFd(-1) {
115 }
116
~WifiForwarder()117 WifiForwarder::~WifiForwarder() {
118 cleanup();
119 }
120
init()121 Result WifiForwarder::init() {
122 if (mMonitorPcap || mPipeFd != -1) {
123 return Result::error("WifiForwarder already initialized");
124 }
125
126 mPipeFd = qemu_pipe_open_ns(NULL, kQemuPipeName, O_RDWR);
127 if (mPipeFd == -1) {
128 // It's OK if this fails, the emulator might not have been started with
129 // this feature enabled. If it's not enabled we'll try again later, in
130 // the meantime there is no point in opening the monitor socket either.
131 LOGE("WifiForwarder unable to open QEMU pipe: %s", strerror(errno));
132 mDeadline = Pollable::Clock::now() + std::chrono::minutes(1);
133 return Result::success();
134 }
135
136 char errorMsg[PCAP_ERRBUF_SIZE];
137 memset(errorMsg, 0, sizeof(errorMsg));
138 mMonitorPcap = pcap_create(mInterfaceName.c_str(), errorMsg);
139 if (mMonitorPcap == nullptr) {
140 return Result::error("WifiForwarder cannot create pcap handle: %s",
141 errorMsg);
142 }
143 int result = pcap_set_snaplen(mMonitorPcap, kPcapSnapLength);
144 if (result != 0) {
145 return Result::error("WifiForwader cannot set pcap snap length: %s",
146 pcap_statustostr(result));
147 }
148
149 result = pcap_set_promisc(mMonitorPcap, 1);
150 if (result != 0) {
151 return Result::error("WifiForwader cannot set pcap promisc mode: %s",
152 pcap_statustostr(result));
153 }
154
155 result = pcap_set_immediate_mode(mMonitorPcap, 1);
156 if (result != 0) {
157 return Result::error("WifiForwader cannot set pcap immediate mode: %s",
158 pcap_statustostr(result));
159 }
160
161 result = pcap_activate(mMonitorPcap);
162 if (result > 0) {
163 // A warning, log it but keep going
164 LOGW("WifiForwader received warnings when activating pcap: %s",
165 pcap_statustostr(result));
166 } else if (result < 0) {
167 // An error, return
168 return Result::error("WifiForwader unable to activate pcap: %s",
169 pcap_statustostr(result));
170 }
171
172 int datalinkType = pcap_datalink(mMonitorPcap);
173 if (datalinkType != DLT_IEEE802_11_RADIO) {
174 // Unexpected data link encapsulation, we don't support this
175 return Result::error("WifiForwarder detected incompatible data link "
176 "encapsulation: %d", datalinkType);
177 }
178 // All done
179 return Result::success();
180 }
181
182
getPollData(std::vector<pollfd> * fds) const183 void WifiForwarder::getPollData(std::vector<pollfd>* fds) const {
184 if (mPipeFd == -1) {
185 return;
186 }
187 int pcapFd = pcap_get_selectable_fd(mMonitorPcap);
188 if (pcapFd != -1) {
189 fds->push_back(pollfd{pcapFd, POLLIN, 0});
190 } else {
191 LOGE("WifiForwarder unable to get pcap fd");
192 }
193 if (mPipeFd != -1) {
194 fds->push_back(pollfd{mPipeFd, POLLIN, 0});
195 }
196 }
197
getTimeout() const198 Pollable::Timestamp WifiForwarder::getTimeout() const {
199 // If there is no pipe return the deadline, we're going to retry, otherwise
200 // use an infinite timeout.
201 return mPipeFd == -1 ? mDeadline : Pollable::Timestamp::max();
202 }
203
onReadAvailable(int fd,int *)204 bool WifiForwarder::onReadAvailable(int fd, int* /*status*/) {
205 if (fd == mPipeFd) {
206 injectFromPipe();
207 } else {
208 forwardFromPcap();
209 }
210 return true;
211 }
212
forwardFromPcap()213 void WifiForwarder::forwardFromPcap() {
214 struct pcap_pkthdr* header = nullptr;
215 const u_char* data = nullptr;
216 int result = pcap_next_ex(mMonitorPcap, &header, &data);
217 if (result == 0) {
218 // Timeout, nothing to do
219 return;
220 } else if (result < 0) {
221 LOGE("WifiForwarder failed to read from pcap: %s",
222 pcap_geterr(mMonitorPcap));
223 return;
224 }
225 if (header->caplen < header->len) {
226 LOGE("WifiForwarder received packet exceeding capture length: %u < %u",
227 header->caplen, header->len);
228 return;
229 }
230
231 if (mPipeFd == -1) {
232 LOGE("WifiForwarder unable to forward data, pipe not open");
233 return;
234 }
235
236 if (header->caplen < sizeof(RadioTapHeader)) {
237 // This packet is too small to be a valid radiotap packet, drop it
238 LOGE("WifiForwarder captured packet that is too small: %u",
239 header->caplen);
240 return;
241 }
242
243 auto radiotap = reinterpret_cast<const RadioTapHeader*>(data);
244 uint32_t radioLen = __le16_to_cpu(radiotap->it_len);
245 if (header->caplen < radioLen + kMinimumIeee80211Size) {
246 // This packet is too small to contain a valid IEEE 802.11 frame
247 LOGE("WifiForwarder captured packet that is too small: %u < %u",
248 header->caplen, radioLen + kMinimumIeee80211Size);
249 return;
250 }
251
252 WifiForwardHeader forwardHeader(header->caplen, radioLen);
253
254 if (qemu_pipe_write_fully(mPipeFd, &forwardHeader, sizeof(forwardHeader))) {
255 LOGE("WifiForwarder failed to write to pipe: %s", strerror(errno));
256 return;
257 }
258
259 if (qemu_pipe_write_fully(mPipeFd, data, header->caplen)) {
260 LOGE("WifiForwarder failed to write to pipe: %s", strerror(errno));
261 return;
262 }
263 }
264
injectFromPipe()265 void WifiForwarder::injectFromPipe() {
266 size_t start = mMonitorBuffer.size();
267 size_t newSize = start + kForwardBufferIncrement;
268 if (newSize > kForwardBufferMaxSize) {
269 // We've exceeded the maximum allowed size, drop everything we have so
270 // far and start over. This is most likely caused by some delay in
271 // injection or the injection failing in which case keeping old data
272 // around isn't going to be very useful.
273 LOGE("WifiForwarder ran out of buffer space");
274 newSize = kForwardBufferIncrement;
275 start = 0;
276 }
277 mMonitorBuffer.resize(newSize);
278
279 while (true) {
280 int result = ::read(mPipeFd,
281 mMonitorBuffer.data() + start,
282 mMonitorBuffer.size() - start);
283 if (result < 0) {
284 if (errno == EINTR) {
285 continue;
286 }
287 LOGE("WifiForwarder failed to read to forward buffer: %s",
288 strerror(errno));
289 // Return the buffer to its previous size
290 mMonitorBuffer.resize(start);
291 return;
292 } else if (result == 0) {
293 // Nothing received, nothing to write
294 // Return the buffer to its previous size
295 mMonitorBuffer.resize(start);
296 LOGE("WifiForwarder did not receive anything to inject");
297 return;
298 }
299 // Adjust the buffer size to match everything we recieved
300 mMonitorBuffer.resize(start + static_cast<size_t>(result));
301 break;
302 }
303
304 while (mMonitorBuffer.size() >=
305 sizeof(WifiForwardHeader) + sizeof(RadioTapHeader)) {
306 auto fwd = reinterpret_cast<WifiForwardHeader*>(mMonitorBuffer.data());
307 if (__le32_to_cpu(fwd->magic) != kWifiForwardMagic) {
308 // We are not properly aligned, this can happen for the first read
309 // if the client or server happens to send something that's in the
310 // middle of a stream. Attempt to find the next packet boundary.
311 LOGE("WifiForwarder found incorrect magic, finding next magic");
312 uint32_t le32magic = __cpu_to_le32(kWifiForwardMagic);
313 auto next = reinterpret_cast<unsigned char*>(
314 ::memmem(mMonitorBuffer.data(), mMonitorBuffer.size(),
315 &le32magic, sizeof(le32magic)));
316 if (next) {
317 // We've found a possible candidate, erase everything before
318 size_t length = next - mMonitorBuffer.data();
319 mMonitorBuffer.erase(mMonitorBuffer.begin(),
320 mMonitorBuffer.begin() + length);
321 continue;
322 } else {
323 // There is no possible candidate, drop everything except the
324 // last three bytes. The last three bytes could possibly be the
325 // start of the next magic without actually triggering the
326 // search above.
327 if (mMonitorBuffer.size() > 3) {
328 mMonitorBuffer.erase(mMonitorBuffer.begin(),
329 mMonitorBuffer.end() - 3);
330 }
331 // In this case there is nothing left to parse so just return
332 // right away.
333 return;
334 }
335 }
336 // The length according to the wifi forward header
337 const size_t fullLength = __le32_to_cpu(fwd->fullLength);
338 const size_t payloadLength = fullLength - sizeof(WifiForwardHeader);
339 const size_t radioLength = __le32_to_cpu(fwd->radioLength);
340 // Get the radio tap header, right after the wifi forward header
341 unsigned char* radioTapLocation = mMonitorBuffer.data() + sizeof(*fwd);
342 auto hdr = reinterpret_cast<RadioTapHeader*>(radioTapLocation);
343 const size_t radioHdrLength = __le16_to_cpu(hdr->it_len);
344
345 if (radioLength != radioHdrLength) {
346 LOGE("WifiForwarder radiotap (%u), forwarder (%u) length mismatch",
347 (unsigned)(radioHdrLength), (unsigned)radioLength);
348 // The wifi forward header radio length does not match up with the
349 // radiotap header length. Either this was not an actual packet
350 // boundary or the packet is malformed. Remove a single byte from
351 // the buffer to trigger a new magic marker search.
352 mMonitorBuffer.erase(mMonitorBuffer.begin(),
353 mMonitorBuffer.begin() + 1);
354 continue;
355 }
356 // At this point we have verified that the magic marker is present and
357 // that the length in the wifi forward header matches the radiotap
358 // header length. We're now reasonably sure this is actually a valid
359 // packet that we can process.
360
361 if (fullLength > mMonitorBuffer.size()) {
362 // We have not received enough data yet, wait for more to arrive.
363 return;
364 }
365
366 if (hdr->it_version != 0) {
367 // Unknown header version, skip this packet because we don't know
368 // how to handle it.
369 LOGE("WifiForwarder encountered unknown radiotap version %u",
370 static_cast<unsigned>(hdr->it_version));
371 mMonitorBuffer.erase(mMonitorBuffer.begin(),
372 mMonitorBuffer.begin() + fullLength);
373 continue;
374 }
375
376 if (mMonitorPcap) {
377 // A sufficient amount of data has arrived, forward it.
378 int result = pcap_inject(mMonitorPcap, hdr, payloadLength);
379 if (result < 0) {
380 LOGE("WifiForwarder failed to inject %" PRIu64 " bytes: %s",
381 static_cast<uint64_t>(payloadLength),
382 pcap_geterr(mMonitorPcap));
383 } else if (static_cast<size_t>(result) < payloadLength) {
384 LOGE("WifiForwarder only injected %d out of %" PRIu64 " bytes",
385 result, static_cast<uint64_t>(payloadLength));
386 }
387 } else {
388 LOGE("WifiForwarder could not forward to monitor, pcap not set up");
389 }
390 mMonitorBuffer.erase(mMonitorBuffer.begin(),
391 mMonitorBuffer.begin() + fullLength);
392 }
393
394 }
395
cleanup()396 void WifiForwarder::cleanup() {
397 if (mMonitorPcap) {
398 pcap_close(mMonitorPcap);
399 mMonitorPcap = nullptr;
400 }
401 if (mPipeFd != -1) {
402 ::close(mPipeFd);
403 mPipeFd = -1;
404 }
405 }
406
onClose(int,int * status)407 bool WifiForwarder::onClose(int /*fd*/, int* status) {
408 // Don't care which fd, just start all over again for simplicity
409 cleanup();
410 Result res = init();
411 if (!res) {
412 *status = 1;
413 return false;
414 }
415 return true;
416 }
417
onTimeout(int * status)418 bool WifiForwarder::onTimeout(int* status) {
419 if (mPipeFd == -1 && mMonitorPcap == nullptr) {
420 Result res = init();
421 if (!res) {
422 *status = 1;
423 return false;
424 }
425 }
426 return true;
427 }
428
429