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