1 // Copyright 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "wifi/wifi_facade.h"
16
17 #include <memory>
18
19 #include "netsim-daemon/src/ffi.rs.h"
20 #include "netsim/config.pb.h"
21 #include "rust/cxx.h"
22 #include "util/log.h"
23 #include "util/string_utils.h"
24 #ifdef NETSIM_ANDROID_EMULATOR
25 #include "android-qemu2-glue/emulation/WifiService.h"
26 #include "android-qemu2-glue/netsim/libslirp_driver.h"
27 #endif
28
29 namespace netsim::wifi {
30 namespace {
31
32 #ifdef NETSIM_ANDROID_EMULATOR
33 std::shared_ptr<android::qemu2::WifiService> wifi_service;
34 #endif
35 ;
36
37 } // namespace
38
39 namespace facade {
40
HandleWifiCallback(const uint8_t * buf,size_t size)41 size_t HandleWifiCallback(const uint8_t *buf, size_t size) {
42 // Broadcast the response to all WiFi chips.
43 std::vector<uint8_t> packet(buf, buf + size);
44 rust::Slice<const uint8_t> packet_slice(packet.data(), packet.size());
45 wifi::facade::HandleWiFiResponse(packet_slice);
46 return size;
47 }
48
Start(const rust::Slice<::std::uint8_t const> proto_bytes)49 void Start(const rust::Slice<::std::uint8_t const> proto_bytes) {
50 #ifdef NETSIM_ANDROID_EMULATOR
51 // Initialize hostapd and slirp inside WiFi Service.
52 config::WiFi config;
53 config.ParseFromArray(proto_bytes.data(), proto_bytes.size());
54
55 android::qemu2::HostapdOptions hostapd = {
56 .disabled = config.hostapd_options().disabled(),
57 .ssid = config.hostapd_options().ssid(),
58 .passwd = config.hostapd_options().passwd()};
59
60 auto host_dns = stringutils::Split(config.slirp_options().host_dns(), ",");
61 android::qemu2::SlirpOptions slirpOpts = {
62 .disabled = config.slirp_options().disabled(),
63 .ipv4 = (config.slirp_options().has_ipv4() ? config.slirp_options().ipv4()
64 : true),
65 .restricted = config.slirp_options().restricted(),
66 .vnet = config.slirp_options().vnet(),
67 .vhost = config.slirp_options().vhost(),
68 .vmask = config.slirp_options().vmask(),
69 .ipv6 = (config.slirp_options().has_ipv6() ? config.slirp_options().ipv6()
70 : true),
71 .vprefix6 = config.slirp_options().vprefix6(),
72 .vprefixLen = (uint8_t)config.slirp_options().vprefixlen(),
73 .vhost6 = config.slirp_options().vhost6(),
74 .vhostname = config.slirp_options().vhostname(),
75 .tftpath = config.slirp_options().tftpath(),
76 .bootfile = config.slirp_options().bootfile(),
77 .dhcpstart = config.slirp_options().dhcpstart(),
78 .dns = config.slirp_options().dns(),
79 .dns6 = config.slirp_options().dns6(),
80 .host_dns = host_dns,
81 };
82 if (!config.slirp_options().host_dns().empty()) {
83 BtsLogInfo("Host DNS server: %s",
84 config.slirp_options().host_dns().c_str());
85 }
86 auto builder = android::qemu2::WifiService::Builder()
87 .withHostapd(hostapd)
88 .withSlirp(slirpOpts)
89 .withOnReceiveCallback(HandleWifiCallback)
90 .withVerboseLogging(true);
91 wifi_service = builder.build();
92 if (!wifi_service->init()) {
93 BtsLogWarn("Failed to initialize wifi service");
94 }
95 #endif
96 }
Stop()97 void Stop() {
98 #ifdef NETSIM_ANDROID_EMULATOR
99 wifi_service->stop();
100 #endif
101 }
102
103 } // namespace facade
104
libslirp_main_loop_wait()105 void libslirp_main_loop_wait() {
106 #ifdef NETSIM_ANDROID_EMULATOR
107 // main_loop_wait is a non-blocking call where fds maintained by the
108 // WiFi service (slirp) are polled and serviced for I/O. When any fd
109 // become ready for I/O, slirp_pollfds_poll() will be invoked to read
110 // from the open sockets therefore incoming packets are serviced.
111 android::qemu2::libslirp_main_loop_wait(true);
112 #endif
113 }
114
HandleWifiRequestCxx(uint32_t chip_id,const rust::Vec<uint8_t> & packet)115 void HandleWifiRequestCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet) {
116 #ifdef NETSIM_ANDROID_EMULATOR
117 // Send the packet to the WiFi service.
118 struct iovec iov[1];
119 iov[0].iov_base = (void *)packet.data();
120 iov[0].iov_len = packet.size();
121 wifi_service->send(android::base::IOVector(iov, iov + 1));
122 #endif
123 }
124
HostapdSendCxx(uint32_t chip_id,const rust::Vec<uint8_t> & packet)125 void HostapdSendCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet) {
126 #ifdef NETSIM_ANDROID_EMULATOR
127 // Send the packet to Hostapd.
128 struct iovec iov[1];
129 iov[0].iov_base = (void *)packet.data();
130 iov[0].iov_len = packet.size();
131 wifi_service->hostapd_send(android::base::IOVector(iov, iov + 1));
132 #endif
133 }
134
LibslirpSendCxx(uint32_t chip_id,const rust::Vec<uint8_t> & packet)135 void LibslirpSendCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet) {
136 #ifdef NETSIM_ANDROID_EMULATOR
137 // Send the packet to libslirp.
138 struct iovec iov[1];
139 iov[0].iov_base = (void *)packet.data();
140 iov[0].iov_len = packet.size();
141 wifi_service->libslirp_send(android::base::IOVector(iov, iov + 1));
142 #endif
143 }
144
145 } // namespace netsim::wifi
146