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