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