"Fossies" - the Fresh Open Source Software Archive 
Member "netxms-3.8.166/src/agent/subagents/aix/net.cpp" (23 Feb 2021, 10440 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "net.cpp" see the
Fossies "Dox" file reference documentation.
1 /*
2 ** NetXMS subagent for AIX
3 ** Copyright (C) 2004-2020 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: net.cpp
20 **
21 **/
22
23 #include "aix_subagent.h"
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <net/if.h>
27 #include <sys/ndd.h>
28 #include <sys/kinfo.h>
29
30 /**
31 * Function getkerninfo() has not documented, but used in IBM examples.
32 * It also doesn't have prototype in headers, so we declare it here.
33 */
34 #if !HAVE_DECL_GETKERNINFO
35 extern "C" int getkerninfo(int, void *, void *, void *);
36 #endif
37
38 /**
39 * Internal interface info structure
40 */
41 typedef struct
42 {
43 char name[IFNAMSIZ];
44 BYTE mac[6];
45 DWORD ip;
46 DWORD netmask;
47 DWORD iftype;
48 } IF_INFO;
49
50 /**
51 * Interface data
52 */
53 static perfstat_netinterface_t *s_ifaceData = NULL;
54 static int s_ifaceDataSize = 0;
55 static time_t s_ifaceDataTimestamp = 0;
56 static Mutex s_ifaceDataLock;
57
58 /**
59 * Clear network data
60 */
61 void ClearNetworkData()
62 {
63 s_ifaceDataLock.lock();
64 free(s_ifaceData);
65 s_ifaceData = 0;
66 s_ifaceDataSize = 0;
67 s_ifaceDataTimestamp = 0;
68 s_ifaceDataLock.unlock();
69 }
70
71 /**
72 * Get data for all interfaces via libperfstat
73 */
74 static bool GetInterfaceData()
75 {
76 int ifCount = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0);
77 if (ifCount < 1)
78 return false;
79
80 if (ifCount != s_ifaceDataSize)
81 {
82 s_ifaceDataSize = ifCount;
83 s_ifaceData = (perfstat_netinterface_t *)realloc(s_ifaceData, sizeof(perfstat_netinterface_t) * ifCount);
84 }
85
86 perfstat_id_t firstIface;
87 strcpy(firstIface.name, FIRST_NETINTERFACE);
88 bool success = perfstat_netinterface(&firstIface, s_ifaceData, sizeof(perfstat_netinterface_t), ifCount) > 0;
89 if (success)
90 s_ifaceDataTimestamp = time(NULL);
91 return success;
92 }
93
94 /**
95 * Get interface data
96 */
97 LONG H_NetInterfaceInfo(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
98 {
99 char ifName[IF_NAMESIZE], *eptr;
100
101 if (!AgentGetParameterArgA(param, 1, ifName, IF_NAMESIZE))
102 {
103 return SYSINFO_RC_ERROR;
104 }
105
106 // Check if we have interface name or index
107 unsigned int ifIndex = (unsigned int)strtoul(ifName, &eptr, 10);
108 if (*eptr == 0)
109 {
110 // Index passed as argument, convert to name
111 if (if_indextoname(ifIndex, ifName) == NULL)
112 {
113 nxlog_debug_tag(AIX_DEBUG_TAG, 7, _T("Unable to resolve interface index %u"), ifIndex);
114 return SYSINFO_RC_ERROR;
115 }
116 }
117
118 s_ifaceDataLock.lock();
119
120 LONG nRet = SYSINFO_RC_SUCCESS;
121 if (time(NULL) - s_ifaceDataTimestamp > 5)
122 {
123 if (!GetInterfaceData())
124 nRet = SYSINFO_RC_ERROR;
125 }
126
127 if (nRet == SYSINFO_RC_SUCCESS)
128 {
129 int i;
130 for(i = 0; i < s_ifaceDataSize; i++)
131 {
132 if (!strcmp(s_ifaceData[i].name, ifName))
133 break;
134 }
135 if (i < s_ifaceDataSize)
136 {
137 switch(CAST_FROM_POINTER(arg, int))
138 {
139 case IF_INFO_DESCRIPTION:
140 ret_mbstring(value, s_ifaceData[i].description);
141 break;
142 case IF_INFO_MTU:
143 ret_int(value, s_ifaceData[i].mtu);
144 break;
145 case IF_INFO_SPEED:
146 ret_uint(value, s_ifaceData[i].bitrate);
147 break;
148 case IF_INFO_BYTES_IN:
149 ret_uint(value, s_ifaceData[i].ibytes);
150 break;
151 case IF_INFO_BYTES_OUT:
152 ret_uint(value, s_ifaceData[i].obytes);
153 break;
154 case IF_INFO_PACKETS_IN:
155 ret_uint(value, s_ifaceData[i].ipackets);
156 break;
157 case IF_INFO_PACKETS_OUT:
158 ret_uint(value, s_ifaceData[i].opackets);
159 break;
160 case IF_INFO_IN_ERRORS:
161 ret_uint(value, s_ifaceData[i].ierrors);
162 break;
163 case IF_INFO_OUT_ERRORS:
164 ret_uint(value, s_ifaceData[i].oerrors);
165 break;
166 default:
167 nRet = SYSINFO_RC_UNSUPPORTED;
168 break;
169 }
170 }
171 else
172 {
173 nRet = SYSINFO_RC_UNSUPPORTED;
174 }
175 }
176
177 s_ifaceDataLock.unlock();
178 return nRet;
179 }
180
181 /**
182 * Get MAC address and type for interface via getkerninfo()
183 */
184 static void GetNDDInfo(char *pszDevice, BYTE *pMacAddr, DWORD *pdwType)
185 {
186 int size = getkerninfo(KINFO_NDD, 0, 0, 0);
187 if (size <= 0)
188 return; // getkerninfo() error
189
190 struct kinfo_ndd *nddp = (struct kinfo_ndd *)MemAlloc(size);
191 if (getkerninfo(KINFO_NDD, nddp, &size, 0) >= 0)
192 {
193 int nrec = size / sizeof(struct kinfo_ndd);
194 for(int i = 0; i < nrec; i++)
195 {
196 if (!strcmp(pszDevice, nddp[i].ndd_name) ||
197 !strcmp(pszDevice, nddp[i].ndd_alias))
198 {
199 memcpy(pMacAddr, nddp[i].ndd_addr, 6);
200 *pdwType = nddp[i].ndd_type;
201 break;
202 }
203 }
204 }
205 MemFree(nddp);
206 }
207
208 /**
209 * Handler for Net.InterfaceNames enum
210 */
211 LONG H_NetInterfaceNames(const TCHAR *pszParam, const TCHAR *pArg, StringList *value, AbstractCommSession *session)
212 {
213 int sock = socket(AF_INET, SOCK_DGRAM, 0);
214 if (sock <= 0)
215 return SYSINFO_RC_ERROR;
216
217 LONG nRet;
218 int nrecs = 32;
219 struct ifconf ifc;
220
221 retry_ifconf:
222 ifc.ifc_len = nrecs * sizeof(struct ifreq);
223 ifc.ifc_buf = (caddr_t)MemAlloc(ifc.ifc_len);
224 #ifdef OSIOCGIFCONF
225 if (ioctl(sock, OSIOCGIFCONF, &ifc) == 0)
226 #else
227 if (ioctl(sock, SIOCGIFCONF, &ifc) == 0)
228 #endif
229 {
230 if (ifc.ifc_len == nrecs * sizeof(struct ifconf))
231 {
232 // Assume overlolad, so increase buffer and retry
233 MemFree(ifc.ifc_buf);
234 nrecs += 32;
235 goto retry_ifconf;
236 }
237
238 StringSet ifnames;
239 nrecs = ifc.ifc_len / sizeof(struct ifreq);
240 for(int i = 0; i < nrecs; i++)
241 {
242 #ifdef UNICODE
243 ifnames.addPreallocated(WideStringFromMBString(ifc.ifc_req[i].ifr_name));
244 #else
245 ifnames.add(ifc.ifc_req[i].ifr_name);
246 #endif
247 }
248
249 auto it = ifnames.iterator();
250 while(it->hasNext())
251 {
252 value->add(it->next());
253 }
254 delete it;
255
256 nRet = SYSINFO_RC_SUCCESS;
257 }
258 else
259 {
260 nRet = SYSINFO_RC_ERROR;
261 }
262
263 MemFree(ifc.ifc_buf);
264 close(sock);
265 return nRet;
266 }
267
268 /**
269 * Handler for Net.InterfaceList enum
270 */
271 LONG H_NetInterfaceList(const TCHAR *pszParam, const TCHAR *pArg, StringList *value, AbstractCommSession *session)
272 {
273 int sock = socket(AF_INET, SOCK_DGRAM, 0);
274 if (sock <= 0)
275 return SYSINFO_RC_ERROR;
276
277 LONG nRet;
278 int nrecs = 32;
279 struct ifconf ifc;
280
281 retry_ifconf:
282 ifc.ifc_len = nrecs * sizeof(struct ifreq);
283 ifc.ifc_buf = (caddr_t)MemAlloc(ifc.ifc_len);
284 #ifdef OSIOCGIFCONF
285 if (ioctl(sock, OSIOCGIFCONF, &ifc) == 0)
286 #else
287 if (ioctl(sock, SIOCGIFCONF, &ifc) == 0)
288 #endif
289 {
290 if (ifc.ifc_len == nrecs * sizeof(struct ifconf))
291 {
292 // Assume overlolad, so increase buffer and retry
293 MemFree(ifc.ifc_buf);
294 nrecs += 32;
295 goto retry_ifconf;
296 }
297
298 nrecs = ifc.ifc_len / sizeof(struct ifreq);
299 IF_INFO *ifl = MemAllocArray<IF_INFO>(nrecs);
300 int nifs = 0;
301 for(int i = 0; i < nrecs; i++)
302 {
303 // Check if interface already in internal table
304 int j;
305 for(j = 0; j < nifs; j++)
306 if (!strcmp(ifl[j].name, ifc.ifc_req[i].ifr_name) &&
307 (((ifc.ifc_req[i].ifr_addr.sa_family == AF_INET) &&
308 (((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->sin_addr.s_addr == ifl[j].ip)) ||
309 (ifc.ifc_req[i].ifr_addr.sa_family != AF_INET) ||
310 (ifl[j].ip == 0)))
311 break;
312 if (j == nifs)
313 {
314 strcpy(ifl[j].name, ifc.ifc_req[i].ifr_name);
315 GetNDDInfo(ifc.ifc_req[i].ifr_name, ifl[j].mac, &ifl[j].iftype);
316 nifs++;
317 }
318
319 // Copy IP address
320 if (ifc.ifc_req[i].ifr_addr.sa_family == AF_INET)
321 {
322 ifl[j].ip = ((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->sin_addr.s_addr;
323
324 struct ifreq ifr;
325 strcpy(ifr.ifr_name, ifc.ifc_req[i].ifr_name);
326 ifr.ifr_addr.sa_family = AF_INET;
327 if (ioctl(sock, SIOCGIFNETMASK, &ifr) == 0)
328 {
329 ifl[j].netmask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
330 }
331 }
332 }
333
334 // Create result list
335 for(int i = 0; i < nifs; i++)
336 {
337 char szBuffer[256], szIpAddr[16], szMacAddr[32];
338 sprintf(szBuffer, "%d %s/%d %d %s %s",
339 if_nametoindex(ifl[i].name),
340 IpToStrA(ntohl(ifl[i].ip), szIpAddr),
341 BitsInMask(ifl[i].netmask), ifl[i].iftype,
342 BinToStrA(ifl[i].mac, 6, szMacAddr), ifl[i].name);
343 #ifdef UNICODE
344 value->addPreallocated(WideStringFromMBString(szBuffer));
345 #else
346 value->add(szBuffer);
347 #endif
348 }
349 MemFree(ifl);
350 nRet = SYSINFO_RC_SUCCESS;
351 }
352 else
353 {
354 nRet = SYSINFO_RC_ERROR;
355 }
356
357 MemFree(ifc.ifc_buf);
358 close(sock);
359 return nRet;
360 }
361
362 /**
363 * Handler for Net.Interface.AdminStatus parameter
364 */
365 LONG H_NetInterfaceStatus(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
366 {
367 int nRet = SYSINFO_RC_ERROR;
368 char ifName[IF_NAMESIZE], *eptr;
369
370 AgentGetParameterArgA(param, 1, ifName, IF_NAMESIZE);
371
372 // Check if we have interface name or index
373 unsigned int ifIndex = (unsigned int)strtoul(ifName, &eptr, 10);
374 if (*eptr == 0)
375 {
376 // Index passed as argument, convert to name
377 if (if_indextoname(ifIndex, ifName) == NULL)
378 {
379 nxlog_debug_tag(AIX_DEBUG_TAG, 7, _T("Unable to resolve interface index %u"), ifIndex);
380 return SYSINFO_RC_ERROR;
381 }
382 }
383
384 int requestedFlag = 0;
385 switch(CAST_FROM_POINTER(arg, int))
386 {
387 case IF_INFO_ADMIN_STATUS:
388 requestedFlag = IFF_UP;
389 break;
390 case IF_INFO_OPER_STATUS:
391 requestedFlag = IFF_RUNNING;
392 break;
393 default:
394 nxlog_debug_tag(AIX_DEBUG_TAG, 7, _T("Internal error in H_NetIfterfaceStatus (invalid flag requested)"));
395 return SYSINFO_RC_ERROR;
396 }
397
398 int nSocket = socket(AF_INET, SOCK_DGRAM, 0);
399 if (nSocket > 0)
400 {
401 struct ifreq ifr;
402 int flags;
403
404 memset(&ifr, 0, sizeof(ifr));
405 strlcpy(ifr.ifr_name, ifName, sizeof(ifr.ifr_name));
406 if (ioctl(nSocket, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0)
407 {
408 if ((ifr.ifr_flags & requestedFlag) == requestedFlag)
409 {
410 // enabled
411 ret_int(value, 1);
412 nRet = SYSINFO_RC_SUCCESS;
413 }
414 else
415 {
416 ret_int(value, 2);
417 nRet = SYSINFO_RC_SUCCESS;
418 }
419 }
420 close(nSocket);
421 }
422
423 return nRet;
424 }