xref: /aosp_15_r20/hardware/interfaces/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1 /*
2  * Copyright (C) 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 <libnetdevice/libnetdevice.h>
18 
19 #include "common.h"
20 #include "ifreqs.h"
21 
22 #include <android-base/logging.h>
23 #include <libnl++/MessageFactory.h>
24 #include <libnl++/Socket.h>
25 
26 #include <arpa/inet.h>
27 #include <ifaddrs.h>
28 #include <linux/can.h>
29 #include <linux/rtnetlink.h>
30 #include <net/if.h>
31 #include <netdb.h>
32 #include <sys/ioctl.h>
33 
34 #include <algorithm>
35 #include <iterator>
36 #include <sstream>
37 
38 namespace android::netdevice {
39 
useSocketDomain(int domain)40 void useSocketDomain(int domain) {
41     ifreqs::socketDomain = domain;
42 }
43 
exists(std::string_view ifname)44 bool exists(std::string_view ifname) {
45     return nametoindex(ifname) != 0;
46 }
47 
up(std::string_view ifname)48 bool up(std::string_view ifname) {
49     auto ifr = ifreqs::fromName(ifname);
50     if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
51     if (ifr.ifr_flags & IFF_UP) return true;
52     ifr.ifr_flags |= IFF_UP;
53     return ifreqs::send(SIOCSIFFLAGS, ifr);
54 }
55 
down(std::string_view ifname)56 bool down(std::string_view ifname) {
57     auto ifr = ifreqs::fromName(ifname);
58     if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
59     if (!(ifr.ifr_flags & IFF_UP)) return true;
60     ifr.ifr_flags &= ~IFF_UP;
61     return ifreqs::send(SIOCSIFFLAGS, ifr);
62 }
63 
toString(const sockaddr * addr)64 static std::string toString(const sockaddr* addr) {
65     char host[NI_MAXHOST];
66     socklen_t addrlen = (addr->sa_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
67     auto res = getnameinfo(addr, addrlen, host, sizeof(host), nullptr, 0, NI_NUMERICHOST);
68     CHECK(res == 0) << "getnameinfo failed: " << gai_strerror(res);
69     return host;
70 }
71 
getifaddrs()72 static std::unique_ptr<ifaddrs, decltype(&freeifaddrs)> getifaddrs() {
73     ifaddrs* addrs = nullptr;
74     CHECK(getifaddrs(&addrs) == 0) << "getifaddrs failed: " << strerror(errno);
75     return {addrs, freeifaddrs};
76 }
77 
getAllAddr4(std::string_view ifname)78 std::set<std::string> getAllAddr4(std::string_view ifname) {
79     std::set<std::string> addresses;
80     auto addrs = getifaddrs();
81     for (ifaddrs* addr = addrs.get(); addr != nullptr; addr = addr->ifa_next) {
82         if (ifname != addr->ifa_name) continue;
83         if (addr->ifa_addr == nullptr) continue;
84         if (addr->ifa_addr->sa_family != AF_INET) continue;
85         addresses.insert(toString(addr->ifa_addr));
86     }
87     return addresses;
88 }
89 
inetAddr(std::string_view addr)90 static in_addr_t inetAddr(std::string_view addr) {
91     auto addrn = inet_addr(std::string(addr).c_str());
92     CHECK(addrn != INADDR_NONE) << "Invalid address " << addr;
93     return addrn;
94 }
95 
prefixLengthToIpv4Netmask(uint8_t prefixlen)96 static in_addr_t prefixLengthToIpv4Netmask(uint8_t prefixlen) {
97     in_addr_t zero = 0;
98     return htonl(~zero << (32 - prefixlen));
99 }
100 
setAddr4(std::string_view ifname,std::string_view addr,std::optional<uint8_t> prefixlen)101 bool setAddr4(std::string_view ifname, std::string_view addr, std::optional<uint8_t> prefixlen) {
102     auto ifr = ifreqs::fromName(ifname);
103     auto ifrAddr = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
104     ifrAddr->sin_family = AF_INET;
105     ifrAddr->sin_addr.s_addr = inetAddr(addr);
106     if (!ifreqs::send(SIOCSIFADDR, ifr)) return false;
107 
108     if (prefixlen.has_value()) {
109         if (*prefixlen < 0 || *prefixlen > 32) {
110             LOG(ERROR) << "Invalid prefix length: " << *prefixlen;
111             return false;
112         }
113         ifr = ifreqs::fromName(ifname);
114         auto ifrNetmask = reinterpret_cast<sockaddr_in*>(&ifr.ifr_netmask);
115         ifrNetmask->sin_family = AF_INET;
116         ifrNetmask->sin_addr.s_addr = prefixLengthToIpv4Netmask(*prefixlen);
117         if (!ifreqs::send(SIOCSIFNETMASK, ifr)) return false;
118     }
119 
120     return true;
121 }
122 
addAddr4(std::string_view ifname,std::string_view addr,uint8_t prefixlen)123 bool addAddr4(std::string_view ifname, std::string_view addr, uint8_t prefixlen) {
124     nl::MessageFactory<ifaddrmsg> req(RTM_NEWADDR, nl::kCreateFlags);
125     req->ifa_family = AF_INET;
126     req->ifa_prefixlen = prefixlen;
127     req->ifa_flags = IFA_F_SECONDARY;
128     req->ifa_index = nametoindex(ifname);
129 
130     auto addrn = inetAddr(addr);
131     req.add(IFLA_ADDRESS, addrn);
132     req.add(IFLA_BROADCAST, addrn);
133 
134     nl::Socket sock(NETLINK_ROUTE);
135     return sock.send(req) && sock.receiveAck(req);
136 }
137 
add(std::string_view dev,std::string_view type)138 bool add(std::string_view dev, std::string_view type) {
139     nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, nl::kCreateFlags);
140     req.add(IFLA_IFNAME, dev);
141 
142     {
143         auto linkinfo = req.addNested(IFLA_LINKINFO);
144         req.addBuffer(IFLA_INFO_KIND, type);
145     }
146 
147     nl::Socket sock(NETLINK_ROUTE);
148     return sock.send(req) && sock.receiveAck(req);
149 }
150 
del(std::string_view dev)151 bool del(std::string_view dev) {
152     nl::MessageFactory<ifinfomsg> req(RTM_DELLINK);
153     req.add(IFLA_IFNAME, dev);
154 
155     nl::Socket sock(NETLINK_ROUTE);
156     return sock.send(req) && sock.receiveAck(req);
157 }
158 
getHwAddr(std::string_view ifname)159 std::optional<hwaddr_t> getHwAddr(std::string_view ifname) {
160     auto ifr = ifreqs::fromName(ifname);
161     if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return std::nullopt;
162 
163     hwaddr_t hwaddr;
164     memcpy(hwaddr.data(), ifr.ifr_hwaddr.sa_data, hwaddr.size());
165     return hwaddr;
166 }
167 
setHwAddr(std::string_view ifname,hwaddr_t hwaddr)168 bool setHwAddr(std::string_view ifname, hwaddr_t hwaddr) {
169     auto ifr = ifreqs::fromName(ifname);
170 
171     // fetch sa_family
172     if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return false;
173 
174     memcpy(ifr.ifr_hwaddr.sa_data, hwaddr.data(), hwaddr.size());
175     return ifreqs::send(SIOCSIFHWADDR, ifr);
176 }
177 
isUp(std::string_view ifname)178 std::optional<bool> isUp(std::string_view ifname) {
179     auto ifr = ifreqs::fromName(ifname);
180     if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
181     return ifr.ifr_flags & IFF_UP;
182 }
183 
hasIpv4(std::string_view ifname)184 static bool hasIpv4(std::string_view ifname) {
185     auto ifr = ifreqs::fromName(ifname);
186     switch (ifreqs::trySend(SIOCGIFADDR, ifr)) {
187         case 0:
188             return true;
189         case EADDRNOTAVAIL:
190         case ENODEV:
191             return false;
192         default:
193             PLOG(WARNING) << "Failed checking IPv4 address";
194             return false;
195     }
196 }
197 
198 struct WaitState {
199     bool present;
200     bool up;
201     bool hasIpv4Addr;
202 
satisfiedandroid::netdevice::WaitState203     bool satisfied(WaitCondition cnd) const {
204         switch (cnd) {
205             case WaitCondition::PRESENT:
206                 return present;
207             case WaitCondition::PRESENT_AND_UP:
208                 return present && up;
209             case WaitCondition::PRESENT_AND_IPV4:
210                 return present && up && hasIpv4Addr;
211             case WaitCondition::DOWN_OR_GONE:
212                 return !present || !up;
213         }
214     }
215 };
216 
toString(WaitCondition cnd)217 static std::string toString(WaitCondition cnd) {
218     switch (cnd) {
219         case WaitCondition::PRESENT:
220             return "become present";
221         case WaitCondition::PRESENT_AND_UP:
222             return "come up";
223         case WaitCondition::PRESENT_AND_IPV4:
224             return "get IPv4 address";
225         case WaitCondition::DOWN_OR_GONE:
226             return "go down";
227     }
228 }
229 
toString(Quantifier quant)230 static std::string toString(Quantifier quant) {
231     switch (quant) {
232         case Quantifier::ALL_OF:
233             return "all of";
234         case Quantifier::ANY_OF:
235             return "any of";
236     }
237 }
238 
toString(const std::set<std::string> & ifnames)239 static std::string toString(const std::set<std::string>& ifnames) {
240     std::stringstream ss;
241     std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
242     auto str = ss.str();
243     str.pop_back();
244     return str;
245 }
246 
waitFor(std::set<std::string> ifnames,WaitCondition cnd,Quantifier quant)247 std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd,
248                                    Quantifier quant) {
249     nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
250 
251     using StatesMap = std::map<std::string, WaitState>;
252     StatesMap states = {};
253     for (const auto ifname : ifnames) {
254         const auto present = exists(ifname);
255         const auto up = present && isUp(ifname).value_or(false);
256         const auto hasIpv4Addr = present && hasIpv4(ifname);
257         states[ifname] = {present, up, hasIpv4Addr};
258     }
259 
260     const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
261         return it.second.satisfied(cnd);
262     };
263     const auto isFullySatisfied = [&states, quant,
264                                    mapConditionChecker]() -> std::optional<std::string> {
265         if (quant == Quantifier::ALL_OF) {
266             if (!std::all_of(states.begin(), states.end(), mapConditionChecker)) return {};
267             return states.begin()->first;
268         } else {  // Quantifier::ANY_OF
269             const auto it = std::find_if(states.begin(), states.end(), mapConditionChecker);
270             if (it == states.end()) return {};
271             return it->first;
272         }
273     };
274 
275     if (const auto iface = isFullySatisfied()) return iface;
276 
277     LOG(DEBUG) << "Waiting for " << toString(quant) << " " << toString(ifnames) << " to "
278                << toString(cnd);
279     for (const auto rawMsg : sock) {
280         if (const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
281             msg.has_value()) {
282             // Interface added / removed
283             const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
284             if (ifnames.count(ifname) == 0) continue;
285 
286             auto& state = states[ifname];
287             state.present = (msg->header.nlmsg_type != RTM_DELLINK);
288             state.up = state.present && (msg->data.ifi_flags & IFF_UP) != 0;
289             if (!state.present) state.hasIpv4Addr = false;
290 
291         } else if (const auto msg =
292                            nl::Message<ifaddrmsg>::parse(rawMsg, {RTM_NEWADDR, RTM_DELADDR});
293                    msg.has_value()) {
294             // Address added / removed
295             const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
296             if (ifnames.count(ifname) == 0) continue;
297 
298             if (msg->header.nlmsg_type == RTM_NEWADDR) {
299                 states[ifname].hasIpv4Addr = true;
300             } else {
301                 // instead of tracking which one got deleted, let's just ask
302                 states[ifname].hasIpv4Addr = hasIpv4(ifname);
303             }
304         }
305 
306         if (const auto iface = isFullySatisfied()) {
307             LOG(DEBUG) << "Finished waiting for " << toString(quant) << " " << toString(ifnames)
308                        << " to " << toString(cnd);
309             return iface;
310         }
311     }
312     LOG(FATAL) << "Can't read Netlink socket";
313     return {};
314 }
315 
316 }  // namespace android::netdevice
317 
operator ==(const android::netdevice::hwaddr_t lhs,const unsigned char rhs[ETH_ALEN])318 bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) {
319     static_assert(lhs.size() == ETH_ALEN);
320     return 0 == memcmp(lhs.data(), rhs, lhs.size());
321 }
322