d9ed7a533e215b52f31c6c4690cd277b375df31c
[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_qwLastDownEventId = 0;
44 m_iPendingStatus = -1;
45 m_iPollCount = 0;
46 m_iRequiredPollCount = 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_qwLastDownEventId = 0;
74 m_iPendingStatus = -1;
75 m_iPollCount = 0;
76 m_iRequiredPollCount = 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_qwLastDownEventId = 0;
107 m_iPendingStatus = -1;
108 m_iPollCount = 0;
109 m_iRequiredPollCount = 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_iRequiredPollCount = 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_iRequiredPollCount);
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 *pSession, UINT32 dwRqId, Queue *pEventQueue,
307 BOOL bClusterSync, SNMP_Transport *pTransport)
308 {
309 m_pPollRequestor = pSession;
310 Node *pNode = getParentNode();
311 if (pNode == NULL)
312 {
313 m_iStatus = STATUS_UNKNOWN;
314 return; // Cannot find parent node, which is VERY strange
315 }
316
317 sendPollerMsg(dwRqId, _T(" Starting status poll on interface %s\r\n"), m_szName);
318 sendPollerMsg(dwRqId, _T(" Current interface status is %s\r\n"), g_szStatusText[m_iStatus]);
319
320 int adminState = IF_ADMIN_STATE_UNKNOWN;
321 int operState = IF_OPER_STATE_UNKNOWN;
322 BOOL bNeedPoll = TRUE;
323
324 // Poll interface using different methods
325 if ((pNode->getFlags() & NF_IS_NATIVE_AGENT) &&
326 (!(pNode->getFlags() & NF_DISABLE_NXCP)) && (!(pNode->getRuntimeFlags() & NDF_AGENT_UNREACHABLE)))
327 {
328 sendPollerMsg(dwRqId, _T(" Retrieving interface status from NetXMS agent\r\n"));
329 pNode->getInterfaceStatusFromAgent(m_dwIfIndex, &adminState, &operState);
330 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from NetXMS agent: adinState=%d operState=%d"), m_dwId, m_szName, adminState, operState);
331 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
332 {
333 sendPollerMsg(dwRqId, POLLER_INFO _T(" Interface status retrieved from NetXMS agent\r\n"));
334 bNeedPoll = FALSE;
335 }
336 else
337 {
338 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Unable to retrieve interface status from NetXMS agent\r\n"));
339 }
340 }
341
342 if (bNeedPoll && (pNode->getFlags() & NF_IS_SNMP) &&
343 (!(pNode->getFlags() & NF_DISABLE_SNMP)) && (!(pNode->getRuntimeFlags() & NDF_SNMP_UNREACHABLE)) &&
344 (pTransport != NULL))
345 {
346 sendPollerMsg(dwRqId, _T(" Retrieving interface status from SNMP agent\r\n"));
347 pNode->getInterfaceStatusFromSNMP(pTransport, m_dwIfIndex, &adminState, &operState);
348 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from SNMP: adminState=%d operState=%d"), m_dwId, m_szName, adminState, operState);
349 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
350 {
351 sendPollerMsg(dwRqId, POLLER_INFO _T(" Interface status retrieved from SNMP agent\r\n"));
352 bNeedPoll = FALSE;
353 }
354 else
355 {
356 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Unable to retrieve interface status from SNMP agent\r\n"));
357 }
358 }
359
360 if (bNeedPoll)
361 {
362 // Pings cannot be used for cluster sync interfaces
363 if ((pNode->getFlags() & NF_DISABLE_ICMP) || bClusterSync || (m_dwIpAddr == 0) || isLoopback())
364 {
365 // Interface doesn't have an IP address, so we can't ping it
366 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface status cannot be determined\r\n"));
367 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot use ping for status check"), m_dwId, m_szName);
368 }
369 else
370 {
371 // Use ICMP ping as a last option
372 UINT32 icmpProxy = 0;
373
374 if (IsZoningEnabled() && (m_zoneId != 0))
375 {
376 Zone *zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
377 if (zone != NULL)
378 {
379 icmpProxy = zone->getIcmpProxy();
380 }
381 }
382
383 if (icmpProxy != 0)
384 {
385 sendPollerMsg(dwRqId, _T(" Starting ICMP ping via proxy\r\n"));
386 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping via proxy [%u]"), m_dwId, m_szName, icmpProxy);
387 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
388 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
389 {
390 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node found: %s"), m_dwId, m_szName, proxyNode->Name());
391 AgentConnection *conn = proxyNode->createAgentConnection();
392 if (conn != NULL)
393 {
394 TCHAR parameter[64], buffer[64];
395
396 _sntprintf(parameter, 64, _T("Icmp.Ping(%s)"), IpToStr(m_dwIpAddr, buffer));
397 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
398 {
399 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy response: \"%s\""), m_dwId, m_szName, buffer);
400 TCHAR *eptr;
401 long value = _tcstol(buffer, &eptr, 10);
402 if ((*eptr == 0) && (value >= 0))
403 {
404 if (value < 10000)
405 {
406 adminState = IF_ADMIN_STATE_UP;
407 operState = IF_OPER_STATE_UP;
408 }
409 else
410 {
411 adminState = IF_ADMIN_STATE_UNKNOWN;
412 operState = IF_OPER_STATE_DOWN;
413 }
414 }
415 }
416 conn->disconnect();
417 delete conn;
418 }
419 else
420 {
421 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot connect to agent on proxy node"), m_dwId, m_szName);
422 sendPollerMsg(dwRqId, POLLER_ERROR _T(" Unable to establish connection with proxy node\r\n"));
423 }
424 }
425 else
426 {
427 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node not available"), m_dwId, m_szName);
428 sendPollerMsg(dwRqId, POLLER_ERROR _T(" ICMP proxy not available\r\n"));
429 }
430 }
431 else // not using ICMP proxy
432 {
433 sendPollerMsg(dwRqId, _T(" Starting ICMP ping\r\n"));
434 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): calling IcmpPing(0x%08X,3,1500,NULL,%d)"), m_dwId, m_szName, htonl(m_dwIpAddr), g_dwPingSize);
435 UINT32 dwPingStatus = IcmpPing(htonl(m_dwIpAddr), 3, 1500, NULL, g_dwPingSize);
436 if (dwPingStatus == ICMP_RAW_SOCK_FAILED)
437 nxlog_write(MSG_RAW_SOCK_FAILED, EVENTLOG_WARNING_TYPE, NULL);
438 if (dwPingStatus == ICMP_SUCCESS)
439 {
440 adminState = IF_ADMIN_STATE_UP;
441 operState = IF_OPER_STATE_UP;
442 }
443 else
444 {
445 adminState = IF_ADMIN_STATE_UNKNOWN;
446 operState = IF_OPER_STATE_DOWN;
447 }
448 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping result %d, adminState=%d, operState=%d"), m_dwId, m_szName, dwPingStatus, adminState, operState);
449 }
450 }
451 }
452
453 // Calculate interface object status based on admin state, oper state, and expected state
454 int oldStatus = m_iStatus;
455 int newStatus;
456 int expectedState = (m_flags & IF_EXPECTED_STATE_MASK) >> 28;
457 switch(adminState)
458 {
459 case IF_ADMIN_STATE_UP:
460 case IF_ADMIN_STATE_UNKNOWN:
461 switch(operState)
462 {
463 case IF_OPER_STATE_UP:
464 newStatus = ((expectedState == IF_EXPECTED_STATE_DOWN) ? STATUS_CRITICAL : STATUS_NORMAL);
465 break;
466 case IF_OPER_STATE_DOWN:
467 newStatus = ((expectedState == IF_EXPECTED_STATE_UP) ? STATUS_CRITICAL : STATUS_NORMAL);
468 break;
469 case IF_OPER_STATE_TESTING:
470 newStatus = STATUS_TESTING;
471 break;
472 default:
473 newStatus = STATUS_UNKNOWN;
474 break;
475 }
476 break;
477 case IF_ADMIN_STATE_DOWN:
478 newStatus = STATUS_DISABLED;
479 break;
480 case IF_ADMIN_STATE_TESTING:
481 newStatus = STATUS_TESTING;
482 break;
483 default:
484 newStatus = STATUS_UNKNOWN;
485 break;
486 }
487
488 // Check 802.1x state
489 if ((pNode->getFlags() & NF_IS_8021X) && isPhysicalPort())
490 {
491 DbgPrintf(5, _T("StatusPoll(%s): Checking 802.1x state for interface %s"), pNode->Name(), m_szName);
492 paeStatusPoll(pSession, dwRqId, pTransport, pNode);
493 if ((m_dot1xPaeAuthState == PAE_STATE_FORCE_UNAUTH) && (newStatus < STATUS_MAJOR))
494 newStatus = STATUS_MAJOR;
495 }
496
497 // Reset status to unknown if node has known network connectivity problems
498 if ((newStatus == STATUS_CRITICAL) && (pNode->getRuntimeFlags() & NDF_NETWORK_PATH_PROBLEM))
499 {
500 newStatus = STATUS_UNKNOWN;
501 DbgPrintf(6, _T("StatusPoll(%s): Status for interface %s reset to UNKNOWN"), pNode->Name(), m_szName);
502 }
503
504 if (newStatus == m_iPendingStatus)
505 {
506 m_iPollCount++;
507 }
508 else
509 {
510 m_iPendingStatus = newStatus;
511 m_iPollCount = 1;
512 }
513
514 int requiredPolls = (m_iRequiredPollCount > 0) ? m_iRequiredPollCount : g_nRequiredPolls;
515 sendPollerMsg(dwRqId, _T(" Interface is %s for %d poll%s (%d poll%s required for status change)\r\n"),
516 g_szStatusText[newStatus], m_iPollCount, (m_iPollCount == 1) ? _T("") : _T("s"),
517 requiredPolls, (requiredPolls == 1) ? _T("") : _T("s"));
518 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): newStatus=%d oldStatus=%d pollCount=%d requiredPolls=%d"),
519 m_dwId, m_szName, newStatus, oldStatus, m_iPollCount, requiredPolls);
520
521 if ((newStatus != oldStatus) && (m_iPollCount >= requiredPolls) && (expectedState != IF_EXPECTED_STATE_IGNORE))
522 {
523 static UINT32 statusToEvent[] =
524 {
525 EVENT_INTERFACE_UP, // Normal
526 EVENT_INTERFACE_UP, // Warning
527 EVENT_INTERFACE_UP, // Minor
528 EVENT_INTERFACE_DOWN, // Major
529 EVENT_INTERFACE_DOWN, // Critical
530 EVENT_INTERFACE_UNKNOWN, // Unknown
531 EVENT_INTERFACE_UNKNOWN, // Unmanaged
532 EVENT_INTERFACE_DISABLED, // Disabled
533 EVENT_INTERFACE_TESTING // Testing
534 };
535 static UINT32 statusToEventInverted[] =
536 {
537 EVENT_INTERFACE_EXPECTED_DOWN, // Normal
538 EVENT_INTERFACE_EXPECTED_DOWN, // Warning
539 EVENT_INTERFACE_EXPECTED_DOWN, // Minor
540 EVENT_INTERFACE_UNEXPECTED_UP, // Major
541 EVENT_INTERFACE_UNEXPECTED_UP, // Critical
542 EVENT_INTERFACE_UNKNOWN, // Unknown
543 EVENT_INTERFACE_UNKNOWN, // Unmanaged
544 EVENT_INTERFACE_DISABLED, // Disabled
545 EVENT_INTERFACE_TESTING // Testing
546 };
547
548 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): status changed from %d to %d"), m_dwId, m_szName, m_iStatus, newStatus);
549 m_iStatus = newStatus;
550 m_iPendingStatus = -1; // Invalidate pending status
551 sendPollerMsg(dwRqId, _T(" Interface status changed to %s\r\n"), g_szStatusText[m_iStatus]);
552 PostEventEx(pEventQueue,
553 (expectedState == IF_EXPECTED_STATE_DOWN) ? statusToEventInverted[m_iStatus] : statusToEvent[m_iStatus],
554 pNode->Id(), "dsaad", m_dwId, m_szName, m_dwIpAddr, m_dwIpNetMask, m_dwIfIndex);
555 }
556 else if (expectedState == IF_EXPECTED_STATE_IGNORE)
557 {
558 m_iStatus = (newStatus <= STATUS_CRITICAL) ? STATUS_NORMAL : newStatus;
559 if (m_iStatus != oldStatus)
560 m_iPendingStatus = -1; // Invalidate pending status
561 }
562
563 LockData();
564 if ((m_iStatus != oldStatus) || (adminState != (int)m_adminState) || (operState != (int)m_operState))
565 {
566 m_adminState = (WORD)adminState;
567 m_operState = (WORD)operState;
568 Modify();
569 }
570 UnlockData();
571
572 sendPollerMsg(dwRqId, _T(" Interface status after poll is %s\r\n"), g_szStatusText[m_iStatus]);
573 sendPollerMsg(dwRqId, _T(" Finished status poll on interface %s\r\n"), m_szName);
574 }
575
576 /**
577 * PAE (802.1x) status poll
578 */
579 void Interface::paeStatusPoll(ClientSession *pSession, UINT32 dwRqId, SNMP_Transport *pTransport, Node *node)
580 {
581 static const TCHAR *paeStateText[] =
582 {
583 _T("UNKNOWN"),
584 _T("INITIALIZE"),
585 _T("DISCONNECTED"),
586 _T("CONNECTING"),
587 _T("AUTHENTICATING"),
588 _T("AUTHENTICATED"),
589 _T("ABORTING"),
590 _T("HELD"),
591 _T("FORCE AUTH"),
592 _T("FORCE UNAUTH"),
593 _T("RESTART")
594 };
595 static const TCHAR *backendStateText[] =
596 {
597 _T("UNKNOWN"),
598 _T("REQUEST"),
599 _T("RESPONSE"),
600 _T("SUCCESS"),
601 _T("FAIL"),
602 _T("TIMEOUT"),
603 _T("IDLE"),
604 _T("INITIALIZE"),
605 _T("IGNORE")
606 };
607 #define PAE_STATE_TEXT(x) ((((int)(x) <= PAE_STATE_RESTART) && ((int)(x) >= 0)) ? paeStateText[(int)(x)] : paeStateText[0])
608 #define BACKEND_STATE_TEXT(x) ((((int)(x) <= BACKEND_STATE_IGNORE) && ((int)(x) >= 0)) ? backendStateText[(int)(x)] : backendStateText[0])
609
610 sendPollerMsg(dwRqId, _T(" Checking port 802.1x status...\r\n"));
611
612 TCHAR oid[256];
613 INT32 paeState = PAE_STATE_UNKNOWN, backendState = BACKEND_STATE_UNKNOWN;
614 bool modified = false;
615
616 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.1.%d"), m_dwIfIndex);
617 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &paeState, sizeof(INT32), 0);
618
619 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.2.%d"), m_dwIfIndex);
620 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &backendState, sizeof(INT32), 0);
621
622 if (m_dot1xPaeAuthState != (WORD)paeState)
623 {
624 sendPollerMsg(dwRqId, _T(" Port PAE state changed to %s...\r\n"), PAE_STATE_TEXT(paeState));
625 modified = true;
626
627 PostEvent(EVENT_8021X_PAE_STATE_CHANGED, node->Id(), "dsdsds", paeState, PAE_STATE_TEXT(paeState),
628 (UINT32)m_dot1xPaeAuthState, PAE_STATE_TEXT(m_dot1xPaeAuthState), m_dwId, m_szName);
629
630 if (paeState == PAE_STATE_FORCE_UNAUTH)
631 {
632 PostEvent(EVENT_8021X_PAE_FORCE_UNAUTH, node->Id(), "ds", m_dwId, m_szName);
633 }
634 }
635
636 if (m_dot1xBackendAuthState != (WORD)backendState)
637 {
638 sendPollerMsg(dwRqId, _T(" Port backend state changed to %s...\r\n"), BACKEND_STATE_TEXT(backendState));
639 modified = true;
640
641 PostEvent(EVENT_8021X_BACKEND_STATE_CHANGED, node->Id(), "dsdsds", backendState, BACKEND_STATE_TEXT(backendState),
642 (UINT32)m_dot1xBackendAuthState, BACKEND_STATE_TEXT(m_dot1xBackendAuthState), m_dwId, m_szName);
643
644 if (backendState == BACKEND_STATE_FAIL)
645 {
646 PostEvent(EVENT_8021X_AUTH_FAILED, node->Id(), "ds", m_dwId, m_szName);
647 }
648 else if (backendState == BACKEND_STATE_TIMEOUT)
649 {
650 PostEvent(EVENT_8021X_AUTH_TIMEOUT, node->Id(), "ds", m_dwId, m_szName);
651 }
652 }
653
654 if (modified)
655 {
656 LockData();
657 m_dot1xPaeAuthState = (WORD)paeState;
658 m_dot1xBackendAuthState = (WORD)backendState;
659 Modify();
660 UnlockData();
661 }
662 }
663
664 /**
665 * Create NXCP message with object's data
666 */
667 void Interface::CreateMessage(CSCPMessage *pMsg)
668 {
669 NetObj::CreateMessage(pMsg);
670 pMsg->SetVariable(VID_IF_INDEX, m_dwIfIndex);
671 pMsg->SetVariable(VID_IF_TYPE, m_dwIfType);
672 pMsg->SetVariable(VID_IF_SLOT, m_slotNumber);
673 pMsg->SetVariable(VID_IF_PORT, m_portNumber);
674 pMsg->SetVariable(VID_IP_NETMASK, m_dwIpNetMask);
675 pMsg->SetVariable(VID_MAC_ADDR, m_bMacAddr, MAC_ADDR_LENGTH);
676 pMsg->SetVariable(VID_FLAGS, m_flags);
677 pMsg->SetVariable(VID_REQUIRED_POLLS, (WORD)m_iRequiredPollCount);
678 pMsg->SetVariable(VID_PEER_NODE_ID, m_peerNodeId);
679 pMsg->SetVariable(VID_PEER_INTERFACE_ID, m_peerInterfaceId);
680 pMsg->SetVariable(VID_DESCRIPTION, m_description);
681 pMsg->SetVariable(VID_ADMIN_STATE, m_adminState);
682 pMsg->SetVariable(VID_OPER_STATE, m_operState);
683 pMsg->SetVariable(VID_DOT1X_PAE_STATE, m_dot1xPaeAuthState);
684 pMsg->SetVariable(VID_DOT1X_BACKEND_STATE, m_dot1xBackendAuthState);
685 pMsg->SetVariable(VID_ZONE_ID, m_zoneId);
686 }
687
688 /**
689 * Modify object from message
690 */
691 UINT32 Interface::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
692 {
693 if (!bAlreadyLocked)
694 LockData();
695
696 // Number of required polls
697 if (pRequest->IsVariableExist(VID_REQUIRED_POLLS))
698 m_iRequiredPollCount = (int)pRequest->GetVariableShort(VID_REQUIRED_POLLS);
699
700 // Expected interface state
701 if (pRequest->IsVariableExist(VID_EXPECTED_STATE))
702 {
703 UINT32 expectedState = pRequest->GetVariableShort(VID_EXPECTED_STATE);
704 m_flags &= ~IF_EXPECTED_STATE_MASK;
705 m_flags |= expectedState << 28;
706 }
707
708 // Flags
709 if (pRequest->IsVariableExist(VID_FLAGS))
710 {
711 UINT32 newFlags = pRequest->GetVariableLong(VID_FLAGS);
712 newFlags &= IF_USER_FLAGS_MASK;
713 m_flags &= ~IF_USER_FLAGS_MASK;
714 m_flags |= newFlags;
715 }
716
717 return NetObj::ModifyFromMessage(pRequest, TRUE);
718 }
719
720 /**
721 * Set expected state for interface
722 */
723 void Interface::setExpectedState(int state)
724 {
725 LockData();
726 m_flags &= ~IF_EXPECTED_STATE_MASK;
727 m_flags |= (UINT32)state << 28;
728 Modify();
729 UnlockData();
730 }
731
732 /**
733 * Wake up node bound to this interface by sending magic packet
734 */
735 UINT32 Interface::wakeUp()
736 {
737 UINT32 dwAddr, dwResult = RCC_NO_MAC_ADDRESS;
738
739 if (memcmp(m_bMacAddr, "\x00\x00\x00\x00\x00\x00", 6))
740 {
741 dwAddr = htonl(m_dwIpAddr | ~m_dwIpNetMask);
742 if (SendMagicPacket(dwAddr, m_bMacAddr, 5))
743 dwResult = RCC_SUCCESS;
744 else
745 dwResult = RCC_COMM_FAILURE;
746 }
747 return dwResult;
748 }
749
750
751 //
752 // Get interface's parent node
753 //
754
755 Node *Interface::getParentNode()
756 {
757 UINT32 i;
758 Node *pNode = NULL;
759
760 LockParentList(FALSE);
761 for(i = 0; i < m_dwParentCount; i++)
762 if (m_pParentList[i]->Type() == OBJECT_NODE)
763 {
764 pNode = (Node *)m_pParentList[i];
765 break;
766 }
767 UnlockParentList();
768 return pNode;
769 }
770
771
772 //
773 // Change interface's IP address
774 //
775
776 void Interface::setIpAddr(UINT32 dwNewAddr)
777 {
778 UpdateInterfaceIndex(m_dwIpAddr, dwNewAddr, this);
779 LockData();
780 m_dwIpAddr = dwNewAddr;
781 Modify();
782 UnlockData();
783 }
784
785
786 //
787 // Change interface's IP subnet mask
788 //
789
790 void Interface::setIpNetMask(UINT32 dwNetMask)
791 {
792 LockData();
793 m_dwIpNetMask = dwNetMask;
794 Modify();
795 UnlockData();
796 }
797
798
799 /**
800 * Update zone ID. New zone ID taken from parent node.
801 */
802 void Interface::updateZoneId()
803 {
804 Node *node = getParentNode();
805 if (node != NULL)
806 {
807 // Unregister from old zone
808 Zone *zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
809 if (zone != NULL)
810 zone->removeFromIndex(this);
811
812 LockData();
813 m_zoneId = node->getZoneId();
814 Modify();
815 UnlockData();
816
817 // Register in new zone
818 zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
819 if (zone != NULL)
820 zone->addToIndex(this);
821 }
822 }
823
824 /**
825 * Handler for object deletion notification
826 */
827 void Interface::onObjectDelete(UINT32 dwObjectId)
828 {
829 if ((m_peerNodeId == dwObjectId) || (m_peerInterfaceId == dwObjectId))
830 {
831 LockData();
832 m_peerNodeId = 0;
833 m_peerInterfaceId = 0;
834 Modify();
835 UnlockData();
836 }
837 NetObj::onObjectDelete(dwObjectId);
838 }