1 /*
2 * Copyright (C) 2017 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 <arpa/inet.h>
18 #include <android-base/logging.h>
19 #include <ifaddrs.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/types.h>
23
24 #include "device_config.h"
25
26 namespace cuttlefish {
27
28 namespace {
29
number_of_ones(unsigned long val)30 uint8_t number_of_ones(unsigned long val) {
31 uint8_t ret = 0;
32 while (val) {
33 ret += val % 2;
34 val >>= 1;
35 }
36 return ret;
37 }
38
39 class NetConfig {
40 public:
41 uint8_t ril_prefixlen = -1;
42 std::string ril_ipaddr;
43 std::string ril_gateway;
44 std::string ril_dns;
45 std::string ril_broadcast;
46
ObtainConfig(const std::string & interface,const std::string & dns)47 bool ObtainConfig(const std::string& interface, const std::string& dns) {
48 bool ret = ParseInterfaceAttributes(interface);
49 if (ret) {
50 ril_dns = dns;
51 LOG(DEBUG) << "Network config:";
52 LOG(DEBUG) << "ipaddr = " << ril_ipaddr;
53 LOG(DEBUG) << "gateway = " << ril_gateway;
54 LOG(DEBUG) << "dns = " << ril_dns;
55 LOG(DEBUG) << "broadcast = " << ril_broadcast;
56 LOG(DEBUG) << "prefix length = " << static_cast<int>(ril_prefixlen);
57 }
58 return ret;
59 }
60
61 private:
ParseInterfaceAttributes(struct ifaddrs * ifa)62 bool ParseInterfaceAttributes(struct ifaddrs* ifa) {
63 struct sockaddr_in* sa;
64 char* addr_str;
65
66 // Gateway
67 sa = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr);
68 addr_str = inet_ntoa(sa->sin_addr);
69 this->ril_gateway = strtok(addr_str, "\n");
70 auto gateway_s_addr = ntohl(sa->sin_addr.s_addr);
71
72 // Broadcast
73 sa = reinterpret_cast<sockaddr_in*>(ifa->ifa_broadaddr);
74 addr_str = inet_ntoa(sa->sin_addr);
75 this->ril_broadcast = strtok(addr_str, "\n");
76 auto broadcast_s_addr = ntohl(sa->sin_addr.s_addr);
77
78 // Detect misconfigured network interfaces. All network interfaces must
79 // have a valid broadcast address set; if there is none set, glibc may
80 // return the interface address in the broadcast field. This causes
81 // no packets to be routed correctly from the guest.
82 if (this->ril_gateway == this->ril_broadcast) {
83 LOG(ERROR) << "Gateway and Broadcast addresses are the same on "
84 << ifa->ifa_name << ", which is invalid.";
85 return false;
86 }
87
88 // Netmask
89 sa = reinterpret_cast<sockaddr_in*>(ifa->ifa_netmask);
90 this->ril_prefixlen = number_of_ones(sa->sin_addr.s_addr);
91 auto netmask_s_addr = ntohl(sa->sin_addr.s_addr);
92
93 // Address (Find an address in the network different than the network, the
94 // gateway and the broadcast)
95 auto network = gateway_s_addr & netmask_s_addr;
96 auto s_addr = network + 1;
97 // s_addr & ~netmask_s_addr is zero when s_addr wraps around the network
98 while (s_addr & ~netmask_s_addr) {
99 if (s_addr != gateway_s_addr && s_addr != broadcast_s_addr) {
100 break;
101 }
102 ++s_addr;
103 }
104 if (s_addr == network) {
105 LOG(ERROR) << "No available address found in interface " << ifa->ifa_name;
106 return false;
107 }
108 struct in_addr addr;
109 addr.s_addr = htonl(s_addr);
110 addr_str = inet_ntoa(addr);
111 this->ril_ipaddr = strtok(addr_str, "\n");
112 return true;
113 }
114
ParseInterfaceAttributes(const std::string & interface)115 bool ParseInterfaceAttributes(const std::string& interface) {
116 struct ifaddrs *ifa_list{}, *ifa{};
117 bool ret = false;
118 getifaddrs(&ifa_list);
119 for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
120 if (strcmp(ifa->ifa_name, interface.c_str()) == 0 &&
121 ifa->ifa_addr->sa_family == AF_INET) {
122 ret = ParseInterfaceAttributes(ifa);
123 break;
124 }
125 }
126 freeifaddrs(ifa_list);
127 return ret;
128 }
129 };
130
CopyChars(char * dest,size_t size,const char * src)131 inline void CopyChars(char* dest, size_t size, const char* src) {
132 auto res = snprintf(dest, size, "%s", src);
133 if (res >= static_cast<int>(size)) {
134 LOG(ERROR) << "Longer(" << res << ") than expected(" << (size - 1)
135 << ") config string was truncated: " << dest;
136 }
137 }
138
139 } // namespace
140
Get()141 std::unique_ptr<DeviceConfig> DeviceConfig::Get() {
142 auto config = CuttlefishConfig::Get();
143 if (!config) return nullptr;
144 std::unique_ptr<DeviceConfig> dev_config(new DeviceConfig());
145 if (!dev_config->InitializeNetworkConfiguration(*config)) {
146 return nullptr;
147 }
148 dev_config->InitializeScreenConfiguration(*config);
149 return dev_config;
150 }
151
InitializeNetworkConfiguration(const CuttlefishConfig & config)152 bool DeviceConfig::InitializeNetworkConfiguration(
153 const CuttlefishConfig& config) {
154 auto instance = config.ForDefaultInstance();
155 NetConfig netconfig;
156 // Check the mobile bridge first; this was the traditional way we configured
157 // the mobile interface. If that fails, it probably means we are using a
158 // newer version of cuttlefish-common, and we can use the tap device
159 // directly instead.
160 if (!netconfig.ObtainConfig(instance.mobile_bridge_name(),
161 config.ril_dns())) {
162 if (!netconfig.ObtainConfig(instance.mobile_tap_name(), config.ril_dns())) {
163 LOG(ERROR) << "Unable to obtain the network configuration";
164 return false;
165 }
166 }
167
168 auto res = snprintf(data_.ril.ipaddr, sizeof(data_.ril.ipaddr), "%s",
169 netconfig.ril_ipaddr.c_str());
170 if (res >= (int)sizeof(data_.ril.ipaddr)) {
171 LOG(ERROR) << "Longer than expected config string was truncated: "
172 << data_.ril.ipaddr;
173 }
174 CopyChars(data_.ril.gateway, sizeof(data_.ril.gateway),
175 netconfig.ril_gateway.c_str());
176 CopyChars(data_.ril.dns, sizeof(data_.ril.dns), netconfig.ril_dns.c_str());
177 CopyChars(data_.ril.broadcast, sizeof(data_.ril.broadcast),
178 netconfig.ril_broadcast.c_str());
179 data_.ril.prefixlen = netconfig.ril_prefixlen;
180
181 generate_address_and_prefix();
182
183 return true;
184 }
185
InitializeScreenConfiguration(const CuttlefishConfig & config)186 void DeviceConfig::InitializeScreenConfiguration(
187 const CuttlefishConfig& config) {
188 data_.screen.x_res = config.x_res();
189 data_.screen.y_res = config.y_res();
190 data_.screen.dpi = config.dpi();
191 data_.screen.refresh_rate = config.refresh_rate_hz();
192 }
193
194 } // namespace cuttlefish
195