• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InitializeNetworkConfiguration(const CuttlefishConfig & cuttlefish_config,DeviceConfig * device_config)131 bool InitializeNetworkConfiguration(const CuttlefishConfig& cuttlefish_config,
132                                     DeviceConfig* device_config) {
133   auto instance = cuttlefish_config.ForDefaultInstance();
134   NetConfig netconfig;
135   // Check the mobile bridge first; this was the traditional way we configured
136   // the mobile interface. If that fails, it probably means we are using a
137   // newer version of cuttlefish-common, and we can use the tap device
138   // directly instead.
139   if (!netconfig.ObtainConfig(instance.mobile_bridge_name(),
140                               instance.ril_dns())) {
141     if (!netconfig.ObtainConfig(instance.mobile_tap_name(),
142                                 instance.ril_dns())) {
143       LOG(ERROR) << "Unable to obtain the network configuration";
144       return false;
145     }
146   }
147 
148   DeviceConfig::RILConfig* ril_config = device_config->mutable_ril_config();
149   ril_config->set_ipaddr(netconfig.ril_ipaddr);
150   ril_config->set_gateway(netconfig.ril_gateway);
151   ril_config->set_dns(netconfig.ril_dns);
152   ril_config->set_broadcast(netconfig.ril_broadcast);
153   ril_config->set_prefixlen(netconfig.ril_prefixlen);
154 
155   return true;
156 }
157 
InitializeScreenConfiguration(const CuttlefishConfig & cuttlefish_config,DeviceConfig * device_config)158 void InitializeScreenConfiguration(const CuttlefishConfig& cuttlefish_config,
159                                    DeviceConfig* device_config) {
160   auto instance = cuttlefish_config.ForDefaultInstance();
161   for (const auto& cuttlefish_display_config : instance.display_configs()) {
162     DeviceConfig::DisplayConfig* device_display_config =
163       device_config->add_display_config();
164 
165     device_display_config->set_width(cuttlefish_display_config.width);
166     device_display_config->set_height(cuttlefish_display_config.height);
167     device_display_config->set_dpi(cuttlefish_display_config.dpi);
168     device_display_config->set_refresh_rate_hz(
169         cuttlefish_display_config.refresh_rate_hz);
170   }
171 }
172 
173 }  // namespace
174 
Get()175 std::unique_ptr<DeviceConfigHelper> DeviceConfigHelper::Get() {
176   auto cuttlefish_config = CuttlefishConfig::Get();
177   if (!cuttlefish_config) {
178     return nullptr;
179   }
180 
181   DeviceConfig device_config;
182   if (!InitializeNetworkConfiguration(*cuttlefish_config, &device_config)) {
183     return nullptr;
184   }
185   InitializeScreenConfiguration(*cuttlefish_config, &device_config);
186 
187   return std::unique_ptr<DeviceConfigHelper>(
188     new DeviceConfigHelper(device_config));
189 }
190 
191 }  // namespace cuttlefish
192