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 "wifi_forwarder.h"
18 
19 #include "frame.h"
20 #include "log.h"
21 
22 static constexpr bool kDebugTraffic = false;
23 static constexpr bool kDebugBeaconTraffic = false;
24 
25 // How many seconds to keep aliases alive for. Since this is used to keep track
26 // of randomized MAC addresses they will expire after a while. Set the value
27 // pretty high to ensure that we don't accidentally lose entries just because
28 // there's not a lot of frames going through.
29 static constexpr auto kAliasesCacheTimeout = std::chrono::hours(8);
30 
WifiForwarder()31 WifiForwarder::WifiForwarder()
32     : mAliases(kAliasesCacheTimeout)
33     , mLocalConnection([this](std::unique_ptr<Frame> frame) {
34                             forwardFrame(std::move(frame), RadioType::Local);
35                        },
__anone7eb97f60202(FrameInfo& info) 36                        [this](FrameInfo& info) { onAck(info, true); },
__anone7eb97f60302(FrameInfo& info) 37                        [this](FrameInfo& info) { onAck(info, false); })
__anone7eb97f60402(std::unique_ptr<Frame> frame) 38     , mRemoteConnection([this](std::unique_ptr<Frame> frame) {
39                             forwardFrame(std::move(frame), RadioType::Remote);
40                         },
__anone7eb97f60502(FrameInfo& info) 41                         [this](FrameInfo& info) { onAck(info, true); },
__anone7eb97f60602(FrameInfo& info) 42                         [this](FrameInfo& info) { onAck(info, false); }) {
43 }
44 
init()45 Result WifiForwarder::init() {
46     auto now = Pollable::Clock::now();
47     Result res = mRemoteConnection.init();
48     if (!res) {
49         // It's OK if this fails, the emulator might not have been started with
50         // this feature enabled. If it's not enabled we'll try again later. If
51         // this does not succeed we don't need to perform the rest of the
52         // initialization either. Just let WiFi work the same as normal.
53         ALOGE("RemoteConnection failed to initialize: %s", res.c_str());
54         mInitDeadline = now + std::chrono::minutes(1);
55         return Result::success();
56     }
57 
58     mAliases.setCurrentTime(now);
59     res = mLocalConnection.init(now);
60     if (!res) {
61         return res;
62     }
63     mDeadline = now + std::chrono::seconds(1);
64     return Result::success();
65 }
66 
getPollData(std::vector<pollfd> * fds) const67 void WifiForwarder::getPollData(std::vector<pollfd>* fds) const {
68     int fd = mLocalConnection.getFd();
69     if (fd >= 0) {
70         struct pollfd pfd = { fd, POLLIN, 0 };
71         fds->push_back(pfd);
72     }
73     fd = mRemoteConnection.getFd();
74     if (fd >= 0) {
75         struct pollfd pfd = { fd, POLLIN, 0 };
76         fds->push_back(pfd);
77     }
78 }
79 
getTimeout() const80 Pollable::Timestamp WifiForwarder::getTimeout() const {
81     if (mRemoteConnection.getFd() == -1) {
82         return mInitDeadline;
83     }
84     return std::min(mLocalConnection.getTimeout(), mDeadline);
85 }
86 
onReadAvailable(int fd,int *)87 bool WifiForwarder::onReadAvailable(int fd, int* /*status*/) {
88     if (fd == mRemoteConnection.getFd()) {
89         mRemoteConnection.receive();
90     } else if (fd == mLocalConnection.getFd()) {
91         mLocalConnection.receive();
92     }
93     return true;
94 }
95 
onClose(int,int *)96 bool WifiForwarder::onClose(int /*fd*/, int* /*status*/) {
97     ALOGE("WifiForwarder socket closed unexpectedly");
98     return false;
99 }
100 
onTimeout(Timestamp now,int *)101 bool WifiForwarder::onTimeout(Timestamp now, int* /*status*/) {
102     bool success = true;
103     if (now >= mInitDeadline) {
104         Result res = init();
105         success = res.isSuccess();
106         if (mRemoteConnection.getFd() == -1) {
107             // Remote connection not set up by init, try again later
108             mInitDeadline = now + std::chrono::minutes(1);
109         }
110     }
111     mLocalConnection.onTimeout(now);
112     if (now >= mDeadline) {
113         mDeadline += std::chrono::seconds(1);
114         mAliases.setCurrentTime(now);
115         mAliases.expireEntries();
116     }
117     return success;
118 }
119 
radioTypeToStr(RadioType type) const120 const char* WifiForwarder::radioTypeToStr(RadioType type) const {
121     switch (type) {
122         case RadioType::Unknown:
123             return "Unknown";
124         case RadioType::Local:
125             return "Local";
126         case RadioType::Remote:
127             return "Remote";
128     }
129 }
130 
onAck(FrameInfo & info,bool success)131 void WifiForwarder::onAck(FrameInfo& info, bool success) {
132     RadioType type = mRadios[info.transmitter()];
133     if (type == RadioType::Remote) {
134         if (kDebugTraffic) {
135             ALOGE("] ACK -] " PRIMAC " [ %" PRIu64 " ] success: %s",
136                   MACARG(info.transmitter()), info.cookie(),
137                   success ? "true" : "false");
138         }
139         if (!mRemoteConnection.ackFrame(info, success)) {
140             ALOGE("WifiForwarder failed to ack remote frame");
141         }
142     } else if (type == RadioType::Local) {
143         if (kDebugTraffic) {
144             ALOGE("> ACK -> " PRIMAC " [ %" PRIu64 " ] success: %s",
145                   MACARG(info.transmitter()), info.cookie(),
146                   success ? "true" : "false");
147         }
148         if (!mLocalConnection.ackFrame(info, success)) {
149             ALOGE("WifiForwarder failed to ack local frame");
150         }
151     } else {
152         ALOGE("Unknown transmitter in ack: " PRIMAC,
153               MACARG(info.transmitter()));
154     }
155 }
156 
forwardFrame(std::unique_ptr<Frame> frame,RadioType sourceType)157 void WifiForwarder::forwardFrame(std::unique_ptr<Frame> frame,
158                                  RadioType sourceType) {
159     if (kDebugTraffic) {
160         if (!frame->isBeacon() || kDebugBeaconTraffic) {
161             bool isRemote = sourceType == RadioType::Remote;
162             ALOGE("%c " PRIMAC " -%c " PRIMAC " %s",
163                   isRemote ? '[' : '<', isRemote ? ']' : '>',
164                   MACARG(frame->source()),
165                   MACARG(frame->destination()),
166                   frame->str().c_str());
167         }
168     }
169 
170     const MacAddress& source = frame->source();
171     const MacAddress& transmitter = frame->transmitter();
172     const MacAddress& destination = frame->destination();
173     auto& currentType = mRadios[transmitter];
174     if (currentType != RadioType::Unknown && currentType != sourceType) {
175         ALOGE("Replacing type for MAC " PRIMAC " of type %s with type %s, "
176               "this might indicate duplicate MACs on different emulators",
177               MACARG(source), radioTypeToStr(currentType),
178               radioTypeToStr(sourceType));
179     }
180     currentType = sourceType;
181     mAliases[source] = transmitter;
182 
183     bool isMulticast = destination.isMulticast();
184     bool sendOnRemote = isMulticast;
185     for (const auto& radio : mRadios) {
186         const MacAddress& radioAddress = radio.first;
187         RadioType radioType = radio.second;
188         if (radioAddress == transmitter) {
189             // Don't send back to the transmitter
190             continue;
191         }
192         if (sourceType == RadioType::Remote && radioType == RadioType::Remote) {
193             // Don't forward frames back to the remote, the remote will have
194             // taken care of this.
195             continue;
196         }
197         bool forward = false;
198         if (isMulticast || destination == radioAddress) {
199             // The frame is either multicast or directly intended for this
200             // radio. Forward it.
201             forward = true;
202         } else {
203             auto alias = mAliases.find(destination);
204             if (alias != mAliases.end() && alias->second == radioAddress) {
205                 // The frame is destined for an address that is a known alias
206                 // for this radio.
207                 forward = true;
208             }
209         }
210         uint32_t seq = 0;
211         if (forward) {
212             switch (radioType) {
213                 case RadioType::Unknown:
214                     ALOGE("Attempted to forward frame to unknown radio type");
215                     break;
216                 case RadioType::Local:
217                     if (kDebugTraffic) {
218                         if (!frame->isBeacon() || kDebugBeaconTraffic) {
219                             ALOGE("> " PRIMAC " -> " PRIMAC " %s",
220                                   MACARG(frame->source()),
221                                   MACARG(frame->destination()),
222                                   frame->str().c_str());
223                         }
224                     }
225                     if (isMulticast) {
226                         // Clone the frame, it might be reused
227                         seq = mLocalConnection.cloneFrame(*frame, radioAddress);
228                     } else {
229                         // This frame has a specific destination, move it
230                         seq = mLocalConnection.transferFrame(std::move(frame),
231                                                              radioAddress);
232                         // Return so that we don't accidentally reuse the frame.
233                         // This should be safe now because it's a unicast frame
234                         // so it should not be sent to multiple radios.
235                         return;
236                     }
237                     break;
238                 case RadioType::Remote:
239                     sendOnRemote = true;
240                     break;
241             }
242         }
243     }
244     if (sendOnRemote && sourceType != RadioType::Remote) {
245         if (kDebugTraffic) {
246             if (!frame->isBeacon() || kDebugBeaconTraffic) {
247                 ALOGE("] " PRIMAC " -] " PRIMAC " %s",
248                       MACARG(frame->source()),
249                       MACARG(frame->destination()),
250                       frame->str().c_str());
251             }
252         }
253         // This is either a multicast message or destined for a radio known to
254         // be a remote. No need to send multiple times to a remote, the remote
255         // will handle that on its own.
256         mRemoteConnection.sendFrame(std::move(frame));
257     }
258 }
259