fixed AIX build issues
[public/netxms.git] / src / agent / subagents / aix / net.cpp
1 /*
2 ** NetXMS subagent for AIX
3 ** Copyright (C) 2004-2014 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 AgentWriteDebugLog(7, _T("AIX: 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 struct kinfo_ndd *nddp;
187 int i, size, nrec;
188
189 size = getkerninfo(KINFO_NDD, 0, 0, 0);
190 if (size <= 0)
191 return; // getkerninfo() error
192
193 nddp = (struct kinfo_ndd *)malloc(size);
194 if (getkerninfo(KINFO_NDD, nddp, &size, 0) >= 0)
195 {
196 nrec = size / sizeof(struct kinfo_ndd);
197 for(i = 0; i < nrec; i++)
198 {
199 if ((!strcmp(pszDevice, nddp[i].ndd_name)) ||
200 (!strcmp(pszDevice, nddp[i].ndd_alias)))
201 {
202 memcpy(pMacAddr, nddp[i].ndd_addr, 6);
203 *pdwType = nddp[i].ndd_type;
204 break;
205 }
206 }
207 }
208 free(nddp);
209 }
210
211 /**
212 * Handler for Net.InterfaceList enum
213 */
214 LONG H_NetInterfaceList(const TCHAR *pszParam, const TCHAR *pArg, StringList *value, AbstractCommSession *session)
215 {
216 LONG nRet;
217 struct ifconf ifc;
218 struct ifreq ifr;
219 IF_INFO *ifl;
220 char szBuffer[256], szIpAddr[16], szMacAddr[32];
221 int i, j, sock, nifs = 0, nrecs = 10;
222
223 sock = socket(AF_INET, SOCK_DGRAM, 0);
224 if (sock <= 0)
225 return SYSINFO_RC_ERROR;
226
227 retry_ifconf:
228 ifc.ifc_len = nrecs * sizeof(struct ifreq);
229 ifc.ifc_buf = (caddr_t)malloc(ifc.ifc_len);
230 #ifdef OSIOCGIFCONF
231 if (ioctl(sock, OSIOCGIFCONF, &ifc) == 0)
232 #else
233 if (ioctl(sock, SIOCGIFCONF, &ifc) == 0)
234 #endif
235 {
236 if (ifc.ifc_len == nrecs * sizeof(struct ifconf))
237 {
238 // Assume overlolad, so increase buffer and retry
239 free(ifc.ifc_buf);
240 nrecs += 10;
241 goto retry_ifconf;
242 }
243
244 nrecs = ifc.ifc_len / sizeof(struct ifreq);
245 ifl = (IF_INFO *)malloc(sizeof(IF_INFO) * nrecs);
246 memset(ifl, 0, sizeof(IF_INFO) * nrecs);
247 for(i = 0, nifs = 0; i < nrecs; i++)
248 {
249 // Check if interface already in internal table
250 for(j = 0; j < nifs; j++)
251 if (!strcmp(ifl[j].name, ifc.ifc_req[i].ifr_name) &&
252 (((ifc.ifc_req[i].ifr_addr.sa_family == AF_INET) &&
253 (((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->sin_addr.s_addr == ifl[j].ip)) ||
254 (ifc.ifc_req[i].ifr_addr.sa_family != AF_INET) ||
255 (ifl[j].ip == 0)))
256 break;
257 if (j == nifs)
258 {
259 strcpy(ifl[j].name, ifc.ifc_req[i].ifr_name);
260 GetNDDInfo(ifc.ifc_req[i].ifr_name, ifl[j].mac, &ifl[j].iftype);
261 nifs++;
262 }
263
264 // Copy IP address
265 if (ifc.ifc_req[i].ifr_addr.sa_family == AF_INET)
266 {
267 ifl[j].ip = ((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->sin_addr.s_addr;
268 strcpy(ifr.ifr_name, ifc.ifc_req[i].ifr_name);
269 ifr.ifr_addr.sa_family = AF_INET;
270 if (ioctl(sock, SIOCGIFNETMASK, &ifr) == 0)
271 {
272 ifl[j].netmask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
273 }
274 }
275 }
276
277 // Create result list
278 for(i = 0; i < nifs; i++)
279 {
280 sprintf(szBuffer, "%d %s/%d %d %s %s",
281 if_nametoindex(ifl[i].name),
282 IpToStrA(ntohl(ifl[i].ip), szIpAddr),
283 BitsInMask(ifl[i].netmask), ifl[i].iftype,
284 BinToStrA(ifl[i].mac, 6, szMacAddr), ifl[i].name);
285 #ifdef UNICODE
286 value->addPreallocated(WideStringFromMBString(szBuffer));
287 #else
288 value->add(szBuffer);
289 #endif
290 }
291 free(ifl);
292 nRet = SYSINFO_RC_SUCCESS;
293 }
294 else
295 {
296 nRet = SYSINFO_RC_ERROR;
297 }
298
299 free(ifc.ifc_buf);
300 close(sock);
301 return nRet;
302 }
303
304 /**
305 * Handler for Net.Interface.AdminStatus parameter
306 */
307 LONG H_NetInterfaceStatus(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
308 {
309 int nRet = SYSINFO_RC_ERROR;
310 char ifName[IF_NAMESIZE], *eptr;
311
312 AgentGetParameterArgA(param, 1, ifName, IF_NAMESIZE);
313
314 // Check if we have interface name or index
315 unsigned int ifIndex = (unsigned int)strtoul(ifName, &eptr, 10);
316 if (*eptr == 0)
317 {
318 // Index passed as argument, convert to name
319 if (if_indextoname(ifIndex, ifName) == NULL)
320 {
321 AgentWriteDebugLog(7, _T("AIX: unable to resolve interface index %u"), ifIndex);
322 return SYSINFO_RC_ERROR;
323 }
324 }
325
326 int requestedFlag = 0;
327 switch(CAST_FROM_POINTER(arg, int))
328 {
329 case IF_INFO_ADMIN_STATUS:
330 requestedFlag = IFF_UP;
331 break;
332 case IF_INFO_OPER_STATUS:
333 requestedFlag = IFF_RUNNING;
334 break;
335 default:
336 AgentWriteDebugLog(7, _T("AIX: internal error in H_NetIfterfaceStatus (invalid flag requested)"));
337 return SYSINFO_RC_ERROR;
338 }
339
340 int nSocket = socket(AF_INET, SOCK_DGRAM, 0);
341 if (nSocket > 0)
342 {
343 struct ifreq ifr;
344 int flags;
345
346 memset(&ifr, 0, sizeof(ifr));
347 strlcpy(ifr.ifr_name, ifName, sizeof(ifr.ifr_name));
348 if (ioctl(nSocket, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0)
349 {
350 if ((ifr.ifr_flags & requestedFlag) == requestedFlag)
351 {
352 // enabled
353 ret_int(value, 1);
354 nRet = SYSINFO_RC_SUCCESS;
355 }
356 else
357 {
358 ret_int(value, 2);
359 nRet = SYSINFO_RC_SUCCESS;
360 }
361 }
362 close(nSocket);
363 }
364
365 return nRet;
366 }