ICMP ping timeout made configurable; code refactoring
[public/netxms.git] / src / server / core / interface.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2013 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: interface.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <ieee8021x.h>
25
26 /**
27 * Default constructor for Interface object
28 */
29 Interface::Interface() : NetObj()
30 {
31 m_flags = 0;
32 nx_strncpy(m_description, m_szName, MAX_DB_STRING);
33 m_dwIpNetMask = 0;
34 m_dwIfIndex = 0;
35 m_dwIfType = IFTYPE_OTHER;
36 m_bridgePortNumber = 0;
37 m_slotNumber = 0;
38 m_portNumber = 0;
39 m_peerNodeId = 0;
40 m_peerInterfaceId = 0;
41 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
42 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
43 m_lastDownEventId = 0;
44 m_pendingStatus = -1;
45 m_pollCount = 0;
46 m_requiredPollCount = 0; // Use system default
47 m_zoneId = 0;
48 }
49
50 /**
51 * Constructor for "fake" interface object
52 */
53 Interface::Interface(UINT32 dwAddr, UINT32 dwNetMask, UINT32 zoneId, bool bSyntheticMask) : NetObj()
54 {
55 m_flags = bSyntheticMask ? IF_SYNTHETIC_MASK : 0;
56 if ((dwAddr & 0xFF000000) == 0x7F000000)
57 m_flags |= IF_LOOPBACK;
58
59 _tcscpy(m_szName, _T("unknown"));
60 _tcscpy(m_description, _T("unknown"));
61 m_dwIpAddr = dwAddr;
62 m_dwIpNetMask = dwNetMask;
63 m_dwIfIndex = 1;
64 m_dwIfType = IFTYPE_OTHER;
65 m_bridgePortNumber = 0;
66 m_slotNumber = 0;
67 m_portNumber = 0;
68 m_peerNodeId = 0;
69 m_peerInterfaceId = 0;
70 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
71 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
72 memset(m_bMacAddr, 0, MAC_ADDR_LENGTH);
73 m_lastDownEventId = 0;
74 m_pendingStatus = -1;
75 m_pollCount = 0;
76 m_requiredPollCount = 0; // Use system default
77 m_zoneId = zoneId;
78 m_isHidden = true;
79 }
80
81 /**
82 * Constructor for normal interface object
83 */
84 Interface::Interface(const TCHAR *name, const TCHAR *descr, UINT32 index, UINT32 ipAddr, UINT32 ipNetMask, UINT32 ifType, UINT32 zoneId)
85 : NetObj()
86 {
87 if (((ipAddr & 0xFF000000) == 0x7F000000) || (ifType == IFTYPE_SOFTWARE_LOOPBACK))
88 m_flags = IF_LOOPBACK;
89 else
90 m_flags = 0;
91
92 nx_strncpy(m_szName, name, MAX_OBJECT_NAME);
93 nx_strncpy(m_description, descr, MAX_DB_STRING);
94 m_dwIfIndex = index;
95 m_dwIfType = ifType;
96 m_dwIpAddr = ipAddr;
97 m_dwIpNetMask = ipNetMask;
98 m_bridgePortNumber = 0;
99 m_slotNumber = 0;
100 m_portNumber = 0;
101 m_peerNodeId = 0;
102 m_peerInterfaceId = 0;
103 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
104 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
105 memset(m_bMacAddr, 0, MAC_ADDR_LENGTH);
106 m_lastDownEventId = 0;
107 m_pendingStatus = -1;
108 m_pollCount = 0;
109 m_requiredPollCount = 0; // Use system default
110 m_zoneId = zoneId;
111 m_isHidden = true;
112 }
113
114 /**
115 * Interface class destructor
116 */
117 Interface::~Interface()
118 {
119 }
120
121 /**
122 * Create object from database record
123 */
124 BOOL Interface::CreateFromDB(UINT32 dwId)
125 {
126 BOOL bResult = FALSE;
127
128 m_dwId = dwId;
129
130 if (!loadCommonProperties())
131 return FALSE;
132
133 DB_STATEMENT hStmt = DBPrepare(g_hCoreDB,
134 _T("SELECT ip_addr,ip_netmask,if_type,if_index,node_id,")
135 _T("mac_addr,flags,required_polls,bridge_port,phy_slot,")
136 _T("phy_port,peer_node_id,peer_if_id,description,")
137 _T("dot1x_pae_state,dot1x_backend_state,admin_state,oper_state FROM interfaces WHERE id=?"));
138 if (hStmt == NULL)
139 return FALSE;
140 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
141
142 DB_RESULT hResult = DBSelectPrepared(hStmt);
143 if (hResult == NULL)
144 {
145 DBFreeStatement(hStmt);
146 return FALSE; // Query failed
147 }
148
149 if (DBGetNumRows(hResult) != 0)
150 {
151 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 0);
152 m_dwIpNetMask = DBGetFieldIPAddr(hResult, 0, 1);
153 m_dwIfType = DBGetFieldULong(hResult, 0, 2);
154 m_dwIfIndex = DBGetFieldULong(hResult, 0, 3);
155 UINT32 nodeId = DBGetFieldULong(hResult, 0, 4);
156 DBGetFieldByteArray2(hResult, 0, 5, m_bMacAddr, MAC_ADDR_LENGTH, 0);
157 m_flags = DBGetFieldULong(hResult, 0, 6);
158 m_requiredPollCount = DBGetFieldLong(hResult, 0, 7);
159 m_bridgePortNumber = DBGetFieldULong(hResult, 0, 8);
160 m_slotNumber = DBGetFieldULong(hResult, 0, 9);
161 m_portNumber = DBGetFieldULong(hResult, 0, 10);
162 m_peerNodeId = DBGetFieldULong(hResult, 0, 11);
163 m_peerInterfaceId = DBGetFieldULong(hResult, 0, 12);
164 DBGetField(hResult, 0, 13, m_description, MAX_DB_STRING);
165 m_dot1xPaeAuthState = (WORD)DBGetFieldLong(hResult, 0, 14);
166 m_dot1xBackendAuthState = (WORD)DBGetFieldLong(hResult, 0, 15);
167 m_adminState = (WORD)DBGetFieldLong(hResult, 0, 16);
168 m_operState = (WORD)DBGetFieldLong(hResult, 0, 17);
169
170 // Link interface to node
171 if (!m_isDeleted)
172 {
173 NetObj *object = FindObjectById(nodeId);
174 if (object == NULL)
175 {
176 nxlog_write(MSG_INVALID_NODE_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, nodeId);
177 }
178 else if (object->Type() != OBJECT_NODE)
179 {
180 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, nodeId);
181 }
182 else
183 {
184 object->AddChild(this);
185 AddParent(object);
186 m_zoneId = ((Node *)object)->getZoneId();
187 bResult = TRUE;
188 }
189 }
190 else
191 {
192 bResult = TRUE;
193 }
194 }
195
196 DBFreeResult(hResult);
197 DBFreeStatement(hStmt);
198
199 // Load access list
200 loadACLFromDB();
201
202 // Validate loopback flag
203 if (((m_dwIpAddr & 0xFF000000) == 0x7F000000) || (m_dwIfType == IFTYPE_SOFTWARE_LOOPBACK))
204 m_flags |= IF_LOOPBACK;
205
206 return bResult;
207 }
208
209 /**
210 * Save interface object to database
211 */
212 BOOL Interface::SaveToDB(DB_HANDLE hdb)
213 {
214 TCHAR szMacStr[16], szIpAddr[16], szNetMask[16];
215 UINT32 dwNodeId;
216
217 LockData();
218
219 if (!saveCommonProperties(hdb))
220 {
221 UnlockData();
222 return FALSE;
223 }
224
225 // Determine owning node's ID
226 Node *pNode = getParentNode();
227 if (pNode != NULL)
228 dwNodeId = pNode->Id();
229 else
230 dwNodeId = 0;
231
232 // Form and execute INSERT or UPDATE query
233 DB_STATEMENT hStmt;
234 if (IsDatabaseRecordExist(hdb, _T("interfaces"), _T("id"), m_dwId))
235 {
236 hStmt = DBPrepare(hdb,
237 _T("UPDATE interfaces SET ip_addr=?,ip_netmask=?,")
238 _T("node_id=?,if_type=?,if_index=?,mac_addr=?,flags=?,")
239 _T("required_polls=?,bridge_port=?,phy_slot=?,phy_port=?,")
240 _T("peer_node_id=?,peer_if_id=?,description=?,admin_state=?,")
241 _T("oper_state=?,dot1x_pae_state=?,dot1x_backend_state=? WHERE id=?"));
242 }
243 else
244 {
245 hStmt = DBPrepare(hdb,
246 _T("INSERT INTO interfaces (ip_addr,ip_netmask,node_id,if_type,if_index,mac_addr,")
247 _T("flags,required_polls,bridge_port,phy_slot,phy_port,peer_node_id,peer_if_id,description,")
248 _T("admin_state,oper_state,dot1x_pae_state,dot1x_backend_state,id) ")
249 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
250 }
251 if (hStmt == NULL)
252 {
253 UnlockData();
254 return FALSE;
255 }
256
257 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, IpToStr(m_dwIpAddr, szIpAddr), DB_BIND_STATIC);
258 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, IpToStr(m_dwIpNetMask, szNetMask), DB_BIND_STATIC);
259 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, dwNodeId);
260 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_dwIfType);
261 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, m_dwIfIndex);
262 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, BinToStr(m_bMacAddr, MAC_ADDR_LENGTH, szMacStr), DB_BIND_STATIC);
263 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, m_flags);
264 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_requiredPollCount);
265 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, m_bridgePortNumber);
266 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, m_slotNumber);
267 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, m_portNumber);
268 DBBind(hStmt, 12, DB_SQLTYPE_INTEGER, m_peerNodeId);
269 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, m_peerInterfaceId);
270 DBBind(hStmt, 14, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC);
271 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (UINT32)m_adminState);
272 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, (UINT32)m_operState);
273 DBBind(hStmt, 17, DB_SQLTYPE_INTEGER, (UINT32)m_dot1xPaeAuthState);
274 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, (UINT32)m_dot1xBackendAuthState);
275 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, m_dwId);
276
277 BOOL success = DBExecute(hStmt);
278 DBFreeStatement(hStmt);
279
280 // Save access list
281 if (success)
282 success = saveACLToDB(hdb);
283
284 // Clear modifications flag and unlock object
285 if (success)
286 m_isModified = false;
287 UnlockData();
288
289 return success;
290 }
291
292 /**
293 * Delete interface object from database
294 */
295 bool Interface::deleteFromDB(DB_HANDLE hdb)
296 {
297 bool success = NetObj::deleteFromDB(hdb);
298 if (success)
299 success = executeQueryOnObject(hdb, _T("DELETE FROM interfaces WHERE id=?"));
300 return success;
301 }
302
303 /**
304 * Perform status poll on interface
305 */
306 void Interface::statusPoll(ClientSession *session, UINT32 rqId, Queue *eventQueue, bool clusterSync, SNMP_Transport *snmpTransport)
307 {
308 m_pollRequestor = session;
309 Node *pNode = getParentNode();
310 if (pNode == NULL)
311 {
312 m_iStatus = STATUS_UNKNOWN;
313 return; // Cannot find parent node, which is VERY strange
314 }
315
316 sendPollerMsg(rqId, _T(" Starting status poll on interface %s\r\n"), m_szName);
317 sendPollerMsg(rqId, _T(" Current interface status is %s\r\n"), g_szStatusText[m_iStatus]);
318
319 int adminState = IF_ADMIN_STATE_UNKNOWN;
320 int operState = IF_OPER_STATE_UNKNOWN;
321 BOOL bNeedPoll = TRUE;
322
323 // Poll interface using different methods
324 if ((pNode->getFlags() & NF_IS_NATIVE_AGENT) &&
325 (!(pNode->getFlags() & NF_DISABLE_NXCP)) && (!(pNode->getRuntimeFlags() & NDF_AGENT_UNREACHABLE)))
326 {
327 sendPollerMsg(rqId, _T(" Retrieving interface status from NetXMS agent\r\n"));
328 pNode->getInterfaceStatusFromAgent(m_dwIfIndex, &adminState, &operState);
329 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from NetXMS agent: adinState=%d operState=%d"), m_dwId, m_szName, adminState, operState);
330 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
331 {
332 sendPollerMsg(rqId, POLLER_INFO _T(" Interface status retrieved from NetXMS agent\r\n"));
333 bNeedPoll = FALSE;
334 }
335 else
336 {
337 sendPollerMsg(rqId, POLLER_WARNING _T(" Unable to retrieve interface status from NetXMS agent\r\n"));
338 }
339 }
340
341 if (bNeedPoll && (pNode->getFlags() & NF_IS_SNMP) &&
342 (!(pNode->getFlags() & NF_DISABLE_SNMP)) && (!(pNode->getRuntimeFlags() & NDF_SNMP_UNREACHABLE)) &&
343 (snmpTransport != NULL))
344 {
345 sendPollerMsg(rqId, _T(" Retrieving interface status from SNMP agent\r\n"));
346 pNode->getInterfaceStatusFromSNMP(snmpTransport, m_dwIfIndex, &adminState, &operState);
347 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from SNMP: adminState=%d operState=%d"), m_dwId, m_szName, adminState, operState);
348 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
349 {
350 sendPollerMsg(rqId, POLLER_INFO _T(" Interface status retrieved from SNMP agent\r\n"));
351 bNeedPoll = FALSE;
352 }
353 else
354 {
355 sendPollerMsg(rqId, POLLER_WARNING _T(" Unable to retrieve interface status from SNMP agent\r\n"));
356 }
357 }
358
359 if (bNeedPoll)
360 {
361 // Pings cannot be used for cluster sync interfaces
362 if ((pNode->getFlags() & NF_DISABLE_ICMP) || clusterSync || (m_dwIpAddr == 0) || isLoopback())
363 {
364 // Interface doesn't have an IP address, so we can't ping it
365 sendPollerMsg(rqId, POLLER_WARNING _T(" Interface status cannot be determined\r\n"));
366 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot use ping for status check"), m_dwId, m_szName);
367 }
368 else
369 {
370 // Use ICMP ping as a last option
371 UINT32 icmpProxy = 0;
372
373 if (IsZoningEnabled() && (m_zoneId != 0))
374 {
375 Zone *zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
376 if (zone != NULL)
377 {
378 icmpProxy = zone->getIcmpProxy();
379 }
380 }
381
382 if (icmpProxy != 0)
383 {
384 sendPollerMsg(rqId, _T(" Starting ICMP ping via proxy\r\n"));
385 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping via proxy [%u]"), m_dwId, m_szName, icmpProxy);
386 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
387 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
388 {
389 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node found: %s"), m_dwId, m_szName, proxyNode->Name());
390 AgentConnection *conn = proxyNode->createAgentConnection();
391 if (conn != NULL)
392 {
393 TCHAR parameter[64], buffer[64];
394
395 _sntprintf(parameter, 64, _T("Icmp.Ping(%s)"), IpToStr(m_dwIpAddr, buffer));
396 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
397 {
398 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy response: \"%s\""), m_dwId, m_szName, buffer);
399 TCHAR *eptr;
400 long value = _tcstol(buffer, &eptr, 10);
401 if ((*eptr == 0) && (value >= 0))
402 {
403 if (value < 10000)
404 {
405 adminState = IF_ADMIN_STATE_UP;
406 operState = IF_OPER_STATE_UP;
407 }
408 else
409 {
410 adminState = IF_ADMIN_STATE_UNKNOWN;
411 operState = IF_OPER_STATE_DOWN;
412 }
413 }
414 }
415 conn->disconnect();
416 delete conn;
417 }
418 else
419 {
420 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot connect to agent on proxy node"), m_dwId, m_szName);
421 sendPollerMsg(rqId, POLLER_ERROR _T(" Unable to establish connection with proxy node\r\n"));
422 }
423 }
424 else
425 {
426 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node not available"), m_dwId, m_szName);
427 sendPollerMsg(rqId, POLLER_ERROR _T(" ICMP proxy not available\r\n"));
428 }
429 }
430 else // not using ICMP proxy
431 {
432 sendPollerMsg(rqId, _T(" Starting ICMP ping\r\n"));
433 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): calling IcmpPing(0x%08X,3,%d,NULL,%d)"), m_dwId, m_szName, htonl(m_dwIpAddr), g_icmpPingTimeout, g_icmpPingSize);
434 UINT32 dwPingStatus = IcmpPing(htonl(m_dwIpAddr), 3, g_icmpPingTimeout, NULL, g_icmpPingSize);
435 if (dwPingStatus == ICMP_RAW_SOCK_FAILED)
436 nxlog_write(MSG_RAW_SOCK_FAILED, EVENTLOG_WARNING_TYPE, NULL);
437 if (dwPingStatus == ICMP_SUCCESS)
438 {
439 adminState = IF_ADMIN_STATE_UP;
440 operState = IF_OPER_STATE_UP;
441 }
442 else
443 {
444 adminState = IF_ADMIN_STATE_UNKNOWN;
445 operState = IF_OPER_STATE_DOWN;
446 }
447 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping result %d, adminState=%d, operState=%d"), m_dwId, m_szName, dwPingStatus, adminState, operState);
448 }
449 }
450 }
451
452 // Calculate interface object status based on admin state, oper state, and expected state
453 int oldStatus = m_iStatus;
454 int newStatus;
455 int expectedState = (m_flags & IF_EXPECTED_STATE_MASK) >> 28;
456 switch(adminState)
457 {
458 case IF_ADMIN_STATE_UP:
459 case IF_ADMIN_STATE_UNKNOWN:
460 switch(operState)
461 {
462 case IF_OPER_STATE_UP:
463 newStatus = ((expectedState == IF_EXPECTED_STATE_DOWN) ? STATUS_CRITICAL : STATUS_NORMAL);
464 break;
465 case IF_OPER_STATE_DOWN:
466 newStatus = ((expectedState == IF_EXPECTED_STATE_UP) ? STATUS_CRITICAL : STATUS_NORMAL);
467 break;
468 case IF_OPER_STATE_TESTING:
469 newStatus = STATUS_TESTING;
470 break;
471 default:
472 newStatus = STATUS_UNKNOWN;
473 break;
474 }
475 break;
476 case IF_ADMIN_STATE_DOWN:
477 newStatus = STATUS_DISABLED;
478 break;
479 case IF_ADMIN_STATE_TESTING:
480 newStatus = STATUS_TESTING;
481 break;
482 default:
483 newStatus = STATUS_UNKNOWN;
484 break;
485 }
486
487 // Check 802.1x state
488 if ((pNode->getFlags() & NF_IS_8021X) && isPhysicalPort())
489 {
490 DbgPrintf(5, _T("StatusPoll(%s): Checking 802.1x state for interface %s"), pNode->Name(), m_szName);
491 paeStatusPoll(session, rqId, snmpTransport, pNode);
492 if ((m_dot1xPaeAuthState == PAE_STATE_FORCE_UNAUTH) && (newStatus < STATUS_MAJOR))
493 newStatus = STATUS_MAJOR;
494 }
495
496 // Reset status to unknown if node has known network connectivity problems
497 if ((newStatus == STATUS_CRITICAL) && (pNode->getRuntimeFlags() & NDF_NETWORK_PATH_PROBLEM))
498 {
499 newStatus = STATUS_UNKNOWN;
500 DbgPrintf(6, _T("StatusPoll(%s): Status for interface %s reset to UNKNOWN"), pNode->Name(), m_szName);
501 }
502
503 if (newStatus == m_pendingStatus)
504 {
505 m_pollCount++;
506 }
507 else
508 {
509 m_pendingStatus = newStatus;
510 m_pollCount = 1;
511 }
512
513 int requiredPolls = (m_requiredPollCount > 0) ? m_requiredPollCount : g_requiredPolls;
514 sendPollerMsg(rqId, _T(" Interface is %s for %d poll%s (%d poll%s required for status change)\r\n"),
515 g_szStatusText[newStatus], m_pollCount, (m_pollCount == 1) ? _T("") : _T("s"),
516 requiredPolls, (requiredPolls == 1) ? _T("") : _T("s"));
517 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): newStatus=%d oldStatus=%d pollCount=%d requiredPolls=%d"),
518 m_dwId, m_szName, newStatus, oldStatus, m_pollCount, requiredPolls);
519
520 if ((newStatus != oldStatus) && (m_pollCount >= requiredPolls) && (expectedState != IF_EXPECTED_STATE_IGNORE))
521 {
522 static UINT32 statusToEvent[] =
523 {
524 EVENT_INTERFACE_UP, // Normal
525 EVENT_INTERFACE_UP, // Warning
526 EVENT_INTERFACE_UP, // Minor
527 EVENT_INTERFACE_DOWN, // Major
528 EVENT_INTERFACE_DOWN, // Critical
529 EVENT_INTERFACE_UNKNOWN, // Unknown
530 EVENT_INTERFACE_UNKNOWN, // Unmanaged
531 EVENT_INTERFACE_DISABLED, // Disabled
532 EVENT_INTERFACE_TESTING // Testing
533 };
534 static UINT32 statusToEventInverted[] =
535 {
536 EVENT_INTERFACE_EXPECTED_DOWN, // Normal
537 EVENT_INTERFACE_EXPECTED_DOWN, // Warning
538 EVENT_INTERFACE_EXPECTED_DOWN, // Minor
539 EVENT_INTERFACE_UNEXPECTED_UP, // Major
540 EVENT_INTERFACE_UNEXPECTED_UP, // Critical
541 EVENT_INTERFACE_UNKNOWN, // Unknown
542 EVENT_INTERFACE_UNKNOWN, // Unmanaged
543 EVENT_INTERFACE_DISABLED, // Disabled
544 EVENT_INTERFACE_TESTING // Testing
545 };
546
547 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): status changed from %d to %d"), m_dwId, m_szName, m_iStatus, newStatus);
548 m_iStatus = newStatus;
549 m_pendingStatus = -1; // Invalidate pending status
550 sendPollerMsg(rqId, _T(" Interface status changed to %s\r\n"), g_szStatusText[m_iStatus]);
551 PostEventEx(eventQueue,
552 (expectedState == IF_EXPECTED_STATE_DOWN) ? statusToEventInverted[m_iStatus] : statusToEvent[m_iStatus],
553 pNode->Id(), "dsaad", m_dwId, m_szName, m_dwIpAddr, m_dwIpNetMask, m_dwIfIndex);
554 }
555 else if (expectedState == IF_EXPECTED_STATE_IGNORE)
556 {
557 m_iStatus = (newStatus <= STATUS_CRITICAL) ? STATUS_NORMAL : newStatus;
558 if (m_iStatus != oldStatus)
559 m_pendingStatus = -1; // Invalidate pending status
560 }
561
562 LockData();
563 if ((m_iStatus != oldStatus) || (adminState != (int)m_adminState) || (operState != (int)m_operState))
564 {
565 m_adminState = (WORD)adminState;
566 m_operState = (WORD)operState;
567 Modify();
568 }
569 UnlockData();
570
571 sendPollerMsg(rqId, _T(" Interface status after poll is %s\r\n"), g_szStatusText[m_iStatus]);
572 sendPollerMsg(rqId, _T(" Finished status poll on interface %s\r\n"), m_szName);
573 }
574
575 /**
576 * PAE (802.1x) status poll
577 */
578 void Interface::paeStatusPoll(ClientSession *pSession, UINT32 rqId, SNMP_Transport *pTransport, Node *node)
579 {
580 static const TCHAR *paeStateText[] =
581 {
582 _T("UNKNOWN"),
583 _T("INITIALIZE"),
584 _T("DISCONNECTED"),
585 _T("CONNECTING"),
586 _T("AUTHENTICATING"),
587 _T("AUTHENTICATED"),
588 _T("ABORTING"),
589 _T("HELD"),
590 _T("FORCE AUTH"),
591 _T("FORCE UNAUTH"),
592 _T("RESTART")
593 };
594 static const TCHAR *backendStateText[] =
595 {
596 _T("UNKNOWN"),
597 _T("REQUEST"),
598 _T("RESPONSE"),
599 _T("SUCCESS"),
600 _T("FAIL"),
601 _T("TIMEOUT"),
602 _T("IDLE"),
603 _T("INITIALIZE"),
604 _T("IGNORE")
605 };
606 #define PAE_STATE_TEXT(x) ((((int)(x) <= PAE_STATE_RESTART) && ((int)(x) >= 0)) ? paeStateText[(int)(x)] : paeStateText[0])
607 #define BACKEND_STATE_TEXT(x) ((((int)(x) <= BACKEND_STATE_IGNORE) && ((int)(x) >= 0)) ? backendStateText[(int)(x)] : backendStateText[0])
608
609 sendPollerMsg(rqId, _T(" Checking port 802.1x status...\r\n"));
610
611 TCHAR oid[256];
612 INT32 paeState = PAE_STATE_UNKNOWN, backendState = BACKEND_STATE_UNKNOWN;
613 bool modified = false;
614
615 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.1.%d"), m_dwIfIndex);
616 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &paeState, sizeof(INT32), 0);
617
618 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.2.%d"), m_dwIfIndex);
619 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &backendState, sizeof(INT32), 0);
620
621 if (m_dot1xPaeAuthState != (WORD)paeState)
622 {
623 sendPollerMsg(rqId, _T(" Port PAE state changed to %s...\r\n"), PAE_STATE_TEXT(paeState));
624 modified = true;
625
626 PostEvent(EVENT_8021X_PAE_STATE_CHANGED, node->Id(), "dsdsds", paeState, PAE_STATE_TEXT(paeState),
627 (UINT32)m_dot1xPaeAuthState, PAE_STATE_TEXT(m_dot1xPaeAuthState), m_dwId, m_szName);
628
629 if (paeState == PAE_STATE_FORCE_UNAUTH)
630 {
631 PostEvent(EVENT_8021X_PAE_FORCE_UNAUTH, node->Id(), "ds", m_dwId, m_szName);
632 }
633 }
634
635 if (m_dot1xBackendAuthState != (WORD)backendState)
636 {
637 sendPollerMsg(rqId, _T(" Port backend state changed to %s...\r\n"), BACKEND_STATE_TEXT(backendState));
638 modified = true;
639
640 PostEvent(EVENT_8021X_BACKEND_STATE_CHANGED, node->Id(), "dsdsds", backendState, BACKEND_STATE_TEXT(backendState),
641 (UINT32)m_dot1xBackendAuthState, BACKEND_STATE_TEXT(m_dot1xBackendAuthState), m_dwId, m_szName);
642
643 if (backendState == BACKEND_STATE_FAIL)
644 {
645 PostEvent(EVENT_8021X_AUTH_FAILED, node->Id(), "ds", m_dwId, m_szName);
646 }
647 else if (backendState == BACKEND_STATE_TIMEOUT)
648 {
649 PostEvent(EVENT_8021X_AUTH_TIMEOUT, node->Id(), "ds", m_dwId, m_szName);
650 }
651 }
652
653 if (modified)
654 {
655 LockData();
656 m_dot1xPaeAuthState = (WORD)paeState;
657 m_dot1xBackendAuthState = (WORD)backendState;
658 Modify();
659 UnlockData();
660 }
661 }
662
663 /**
664 * Create NXCP message with object's data
665 */
666 void Interface::CreateMessage(CSCPMessage *pMsg)
667 {
668 NetObj::CreateMessage(pMsg);
669 pMsg->SetVariable(VID_IF_INDEX, m_dwIfIndex);
670 pMsg->SetVariable(VID_IF_TYPE, m_dwIfType);
671 pMsg->SetVariable(VID_IF_SLOT, m_slotNumber);
672 pMsg->SetVariable(VID_IF_PORT, m_portNumber);
673 pMsg->SetVariable(VID_IP_NETMASK, m_dwIpNetMask);
674 pMsg->SetVariable(VID_MAC_ADDR, m_bMacAddr, MAC_ADDR_LENGTH);
675 pMsg->SetVariable(VID_FLAGS, m_flags);
676 pMsg->SetVariable(VID_REQUIRED_POLLS, (WORD)m_requiredPollCount);
677 pMsg->SetVariable(VID_PEER_NODE_ID, m_peerNodeId);
678 pMsg->SetVariable(VID_PEER_INTERFACE_ID, m_peerInterfaceId);
679 pMsg->SetVariable(VID_DESCRIPTION, m_description);
680 pMsg->SetVariable(VID_ADMIN_STATE, m_adminState);
681 pMsg->SetVariable(VID_OPER_STATE, m_operState);
682 pMsg->SetVariable(VID_DOT1X_PAE_STATE, m_dot1xPaeAuthState);
683 pMsg->SetVariable(VID_DOT1X_BACKEND_STATE, m_dot1xBackendAuthState);
684 pMsg->SetVariable(VID_ZONE_ID, m_zoneId);
685 }
686
687 /**
688 * Modify object from message
689 */
690 UINT32 Interface::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
691 {
692 if (!bAlreadyLocked)
693 LockData();
694
695 // Number of required polls
696 if (pRequest->IsVariableExist(VID_REQUIRED_POLLS))
697 m_requiredPollCount = (int)pRequest->GetVariableShort(VID_REQUIRED_POLLS);
698
699 // Expected interface state
700 if (pRequest->IsVariableExist(VID_EXPECTED_STATE))
701 {
702 UINT32 expectedState = pRequest->GetVariableShort(VID_EXPECTED_STATE);
703 m_flags &= ~IF_EXPECTED_STATE_MASK;
704 m_flags |= expectedState << 28;
705 }
706
707 // Flags
708 if (pRequest->IsVariableExist(VID_FLAGS))
709 {
710 UINT32 newFlags = pRequest->GetVariableLong(VID_FLAGS);
711 newFlags &= IF_USER_FLAGS_MASK;
712 m_flags &= ~IF_USER_FLAGS_MASK;
713 m_flags |= newFlags;
714 }
715
716 return NetObj::ModifyFromMessage(pRequest, TRUE);
717 }
718
719 /**
720 * Set expected state for interface
721 */
722 void Interface::setExpectedState(int state)
723 {
724 LockData();
725 m_flags &= ~IF_EXPECTED_STATE_MASK;
726 m_flags |= (UINT32)state << 28;
727 Modify();
728 UnlockData();
729 }
730
731 /**
732 * Wake up node bound to this interface by sending magic packet
733 */
734 UINT32 Interface::wakeUp()
735 {
736 UINT32 dwAddr, dwResult = RCC_NO_MAC_ADDRESS;
737
738 if (memcmp(m_bMacAddr, "\x00\x00\x00\x00\x00\x00", 6))
739 {
740 dwAddr = htonl(m_dwIpAddr | ~m_dwIpNetMask);
741 if (SendMagicPacket(dwAddr, m_bMacAddr, 5))
742 dwResult = RCC_SUCCESS;
743 else
744 dwResult = RCC_COMM_FAILURE;
745 }
746 return dwResult;
747 }
748
749
750 //
751 // Get interface's parent node
752 //
753
754 Node *Interface::getParentNode()
755 {
756 UINT32 i;
757 Node *pNode = NULL;
758
759 LockParentList(FALSE);
760 for(i = 0; i < m_dwParentCount; i++)
761 if (m_pParentList[i]->Type() == OBJECT_NODE)
762 {
763 pNode = (Node *)m_pParentList[i];
764 break;
765 }
766 UnlockParentList();
767 return pNode;
768 }
769
770
771 //
772 // Change interface's IP address
773 //
774
775 void Interface::setIpAddr(UINT32 dwNewAddr)
776 {
777 UpdateInterfaceIndex(m_dwIpAddr, dwNewAddr, this);
778 LockData();
779 m_dwIpAddr = dwNewAddr;
780 Modify();
781 UnlockData();
782 }
783
784
785 //
786 // Change interface's IP subnet mask
787 //
788
789 void Interface::setIpNetMask(UINT32 dwNetMask)
790 {
791 LockData();
792 m_dwIpNetMask = dwNetMask;
793 Modify();
794 UnlockData();
795 }
796
797
798 /**
799 * Update zone ID. New zone ID taken from parent node.
800 */
801 void Interface::updateZoneId()
802 {
803 Node *node = getParentNode();
804 if (node != NULL)
805 {
806 // Unregister from old zone
807 Zone *zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
808 if (zone != NULL)
809 zone->removeFromIndex(this);
810
811 LockData();
812 m_zoneId = node->getZoneId();
813 Modify();
814 UnlockData();
815
816 // Register in new zone
817 zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
818 if (zone != NULL)
819 zone->addToIndex(this);
820 }
821 }
822
823 /**
824 * Handler for object deletion notification
825 */
826 void Interface::onObjectDelete(UINT32 dwObjectId)
827 {
828 if ((m_peerNodeId == dwObjectId) || (m_peerInterfaceId == dwObjectId))
829 {
830 LockData();
831 m_peerNodeId = 0;
832 m_peerInterfaceId = 0;
833 Modify();
834 UnlockData();
835 }
836 NetObj::onObjectDelete(dwObjectId);
837 }