blob: 64a913cb9ef5c4422d96e7a8c8ea0bd8f8b845b7 [file] [log] [blame]
Ratan Gupta3681a502017-06-17 19:20:04 +05301#include "util.hpp"
Ratan Gupta068a8cf2017-07-11 19:18:29 +05302
Ratan Gupta11cef802017-05-29 08:41:48 +05303#include "xyz/openbmc_project/Common/error.hpp"
4
5#include <phosphor-logging/log.hpp>
6#include <phosphor-logging/elog-errors.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +05307
Ratan Gupta3681a502017-06-17 19:20:04 +05308#include <arpa/inet.h>
9#include <dirent.h>
10#include <net/if.h>
11
Ratan Gupta8804feb2017-05-25 10:49:57 +053012#include <iostream>
13#include <list>
14#include <string>
15#include <algorithm>
Ratan Gupta8804feb2017-05-25 10:49:57 +053016
17namespace phosphor
18{
19namespace network
20{
21namespace
22{
23
24using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053025using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta8804feb2017-05-25 10:49:57 +053026
27uint8_t toV6Cidr(const std::string& subnetMask)
28{
29 uint8_t pos = 0;
30 uint8_t prevPos = 0;
31 uint8_t cidr = 0;
32 uint16_t buff {};
33 do
34 {
35 //subnet mask look like ffff:ffff::
36 // or ffff:c000::
37 pos = subnetMask.find(":", prevPos);
38 if (pos == std::string::npos)
39 {
40 break;
41 }
42
43 auto str = subnetMask.substr(prevPos, (pos - prevPos));
44 prevPos = pos + 1;
45
46 // String length is 0
47 if (!str.length())
48 {
49 return cidr;
50 }
51 //converts it into number.
52 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
53 {
54 log<level::ERR>("Invalid Mask",
55 entry("SUBNETMASK=%s", subnetMask));
56
57 return 0;
58 }
59
60 // convert the number into bitset
61 // and check for how many ones are there.
62 // if we don't have all the ones then make
63 // sure that all the ones should be left justify.
64
65 if (__builtin_popcount(buff) != 16)
66 {
67 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) != __builtin_popcount(buff))
68 {
69 log<level::ERR>("Invalid Mask",
70 entry("SUBNETMASK=%s", subnetMask));
71
72 return 0;
73 }
74 cidr += __builtin_popcount(buff);
75 return cidr;
76 }
77
78 cidr += 16;
79 }
80 while (1);
81
82 return cidr;
83}
84}// anonymous namespace
85
86uint8_t toCidr(int addressFamily, const std::string& subnetMask)
87{
88 if (addressFamily == AF_INET6)
89 {
90 return toV6Cidr(subnetMask);
91 }
92
93 uint32_t buff;
94
95 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
96 if (rc <= 0)
97 {
98 log<level::ERR>("inet_pton failed:",
Ratan Gupta11cef802017-05-29 08:41:48 +053099 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530100 return 0;
101 }
102
103 buff = be32toh(buff);
104 // total no of bits - total no of leading zero == total no of ones
105 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
106 {
107 return __builtin_popcount(buff);
108 }
109 else
110 {
111 log<level::ERR>("Invalid Mask",
Ratan Gupta11cef802017-05-29 08:41:48 +0530112 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530113 return 0;
114 }
115}
116
117std::string toMask(int addressFamily, uint8_t prefix)
118{
119 if (addressFamily == AF_INET6)
120 {
121 //TODO:- conversion for v6
122 return "";
123 }
124
125 if (prefix < 1 || prefix > 30)
126 {
127 log<level::ERR>("Invalid Prefix",
128 entry("PREFIX=%d", prefix));
129 return "";
130 }
131 /* Create the netmask from the number of bits */
132 unsigned long mask = 0;
133 for (auto i = 0 ; i < prefix ; i++)
134 {
135 mask |= 1 << (31 - i);
136 }
137 struct in_addr netmask;
138 netmask.s_addr = htonl(mask);
139 return inet_ntoa(netmask);
140}
141
Ratan Gupta11cef802017-05-29 08:41:48 +0530142std::string getNetworkID(int addressFamily, const std::string& ipaddress,
143 uint8_t prefix)
144{
145 unsigned char* pntMask = nullptr;
146 unsigned char* pntNetwork = nullptr;
147 int bit {};
148 int offset {};
149 struct in6_addr netmask {};
150 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
151 0xf8, 0xfc, 0xfe, 0xff
152 };
153
154 pntMask = reinterpret_cast<unsigned char*>(&netmask);
155
156 offset = prefix / 8;
157 bit = prefix % 8;
158
159 while (offset--)
160 {
161 *pntMask++ = 0xff;
162 }
163
164 if (bit)
165 {
166 *pntMask = maskbit[bit];
167 }
168
169 // convert ipaddres string into network address
170 struct in6_addr ipaddressNetwork;
171 if (inet_pton(addressFamily, ipaddress.c_str(), &ipaddressNetwork) <= 0)
172 {
173 log<level::ERR>("inet_pton failure",
174 entry("IPADDRESS=%s",ipaddress.c_str()));
175 report<InternalFailure>();
176
177 return "";
178 }
179
180 // Now bit wise and gets you the network address
181 pntMask = reinterpret_cast<unsigned char*>(&netmask);
182 pntNetwork = reinterpret_cast<unsigned char*>(&ipaddressNetwork);
183
184 for (int i = 0; i < 16 ; i++)
185 {
186 pntNetwork[i] = pntNetwork[i] & pntMask[i];
187 }
188
189 //convert the network address into string fomat.
190 char networkString[INET6_ADDRSTRLEN] = { 0 };
191 if (inet_ntop(addressFamily, &ipaddressNetwork, networkString,
192 INET6_ADDRSTRLEN) == NULL)
193 {
194 log<level::ERR>("inet_ntop failure");
195 report<InternalFailure>();
196 }
197 return networkString;
198}
199
Ratan Gupta8804feb2017-05-25 10:49:57 +0530200bool isLinkLocal(const std::string& address)
201{
202 std::string linklocal = "fe80";
203 return std::mismatch(linklocal.begin(), linklocal.end(),
204 address.begin()).first == linklocal.end() ?
205 true : false;
206}
207
Ratan Gupta3681a502017-06-17 19:20:04 +0530208IntfAddrMap getInterfaceAddrs()
209{
210 IntfAddrMap intfMap{};
211 AddrList addrList{};
212 struct ifaddrs* ifaddr = nullptr;
213
214 // attempt to fill struct with ifaddrs
215 if (getifaddrs(&ifaddr) == -1)
216 {
217 auto error = errno;
218 log<level::ERR>("Error occurred during the getifaddrs call",
219 entry("ERRNO=%s", strerror(error)));
220 elog<InternalFailure>();
221 }
222
223 AddrPtr ifaddrPtr(ifaddr);
224 ifaddr = nullptr;
225
226 std::string intfName{};
227
228 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
229 {
230 // walk interfaces
231 if (ifa->ifa_addr == nullptr)
232 {
233 continue;
234 }
235
236 // get only INET interfaces not ipv6
237 if (ifa->ifa_addr->sa_family == AF_INET ||
238 ifa->ifa_addr->sa_family == AF_INET6)
239 {
240 // if loopback, or not running ignore
241 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
242 !(ifa->ifa_flags & IFF_RUNNING))
243 {
244 continue;
245 }
246 // if the interface name is not same as the previous
247 // iteration then add the addr list into
248 // the map.
249 if (intfName != "" && intfName != std::string(ifa->ifa_name))
250 {
251 intfMap.emplace(intfName, addrList);
252 addrList.clear();
253 }
254 intfName = ifa->ifa_name;
255 AddrInfo info{};
256 char ip[INET6_ADDRSTRLEN] = { 0 };
257 char subnetMask[INET6_ADDRSTRLEN] = { 0 };
258
259 if (ifa->ifa_addr->sa_family == AF_INET)
260 {
261
262 inet_ntop(ifa->ifa_addr->sa_family,
263 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
264 ip,
265 sizeof(ip));
266
267 inet_ntop(ifa->ifa_addr->sa_family,
268 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
269 subnetMask,
270 sizeof(subnetMask));
271
272 }
273 else
274 {
275 inet_ntop(ifa->ifa_addr->sa_family,
276 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
277 ip,
278 sizeof(ip));
279
280 inet_ntop(ifa->ifa_addr->sa_family,
281 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
282 subnetMask,
283 sizeof(subnetMask));
284
285 }
286
287 info.addrType = ifa->ifa_addr->sa_family;
288 info.ipaddress = ip;
289 info.prefix = toCidr(info.addrType, std::string(subnetMask));
290 addrList.emplace_back(info);
291 }
292 }
293 intfMap.emplace(intfName, addrList);
294 return intfMap;
295}
296
Ratan Gupta8804feb2017-05-25 10:49:57 +0530297}//namespace network
298}//namespace phosphor