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