e6f5b9220764a9841489fd77f5b20725db54cae2
[public/netxms.git] / src / server / core / interface.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 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_parentInterfaceId = 0;
32 nx_strncpy(m_description, m_name, MAX_DB_STRING);
33 m_alias[0] = 0;
34 m_index = 0;
35 m_type = IFTYPE_OTHER;
36 m_mtu = 0;
37 m_speed = 0;
38 m_bridgePortNumber = 0;
39 m_slotNumber = 0;
40 m_portNumber = 0;
41 m_peerNodeId = 0;
42 m_peerInterfaceId = 0;
43 m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN;
44 m_adminState = IF_ADMIN_STATE_UNKNOWN;
45 m_operState = IF_OPER_STATE_UNKNOWN;
46 m_pendingOperState = IF_OPER_STATE_UNKNOWN;
47 m_confirmedOperState = IF_OPER_STATE_UNKNOWN;
48 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
49 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
50 memset(m_macAddr, 0, MAC_ADDR_LENGTH);
51 m_lastDownEventId = 0;
52 m_pendingStatus = -1;
53 m_statusPollCount = 0;
54 m_operStatePollCount = 0;
55 m_requiredPollCount = 0; // Use system default
56 m_zoneUIN = 0;
57 m_pingTime = PING_TIME_TIMEOUT;
58 m_pingLastTimeStamp = 0;
59 m_ifTableSuffixLen = 0;
60 m_ifTableSuffix = NULL;
61 }
62
63 /**
64 * Constructor for "fake" interface object
65 */
66 Interface::Interface(const InetAddressList& addrList, UINT32 zoneUIN, bool bSyntheticMask) : NetObj()
67 {
68 m_parentInterfaceId = 0;
69 m_flags = bSyntheticMask ? IF_SYNTHETIC_MASK : 0;
70 if (addrList.isLoopbackOnly())
71 m_flags |= IF_LOOPBACK;
72
73 _tcscpy(m_name, _T("unknown"));
74 _tcscpy(m_description, _T("unknown"));
75 m_alias[0] = 0;
76 m_ipAddressList.add(addrList);
77 m_index = 1;
78 m_type = IFTYPE_OTHER;
79 m_mtu = 0;
80 m_speed = 0;
81 m_bridgePortNumber = 0;
82 m_slotNumber = 0;
83 m_portNumber = 0;
84 m_peerNodeId = 0;
85 m_peerInterfaceId = 0;
86 m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN;
87 m_adminState = IF_ADMIN_STATE_UNKNOWN;
88 m_operState = IF_OPER_STATE_UNKNOWN;
89 m_pendingOperState = IF_OPER_STATE_UNKNOWN;
90 m_confirmedOperState = IF_OPER_STATE_UNKNOWN;
91 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
92 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
93 memset(m_macAddr, 0, MAC_ADDR_LENGTH);
94 m_lastDownEventId = 0;
95 m_pendingStatus = -1;
96 m_statusPollCount = 0;
97 m_operStatePollCount = 0;
98 m_requiredPollCount = 0; // Use system default
99 m_zoneUIN = zoneUIN;
100 m_isHidden = true;
101 m_pingTime = PING_TIME_TIMEOUT;
102 m_pingLastTimeStamp = 0;
103 m_ifTableSuffixLen = 0;
104 m_ifTableSuffix = NULL;
105 }
106
107 /**
108 * Constructor for normal interface object
109 */
110 Interface::Interface(const TCHAR *name, const TCHAR *descr, UINT32 index, const InetAddressList& addrList, UINT32 ifType, UINT32 zoneUIN)
111 : NetObj()
112 {
113 if ((ifType == IFTYPE_SOFTWARE_LOOPBACK) || addrList.isLoopbackOnly())
114 m_flags = IF_LOOPBACK;
115 else
116 m_flags = 0;
117
118 m_parentInterfaceId = 0;
119 nx_strncpy(m_name, name, MAX_OBJECT_NAME);
120 nx_strncpy(m_description, descr, MAX_DB_STRING);
121 m_alias[0] = 0;
122 m_index = index;
123 m_type = ifType;
124 m_mtu = 0;
125 m_speed = 0;
126 m_ipAddressList.add(addrList);
127 m_bridgePortNumber = 0;
128 m_slotNumber = 0;
129 m_portNumber = 0;
130 m_peerNodeId = 0;
131 m_peerInterfaceId = 0;
132 m_adminState = IF_ADMIN_STATE_UNKNOWN;
133 m_operState = IF_OPER_STATE_UNKNOWN;
134 m_pendingOperState = IF_OPER_STATE_UNKNOWN;
135 m_confirmedOperState = IF_OPER_STATE_UNKNOWN;
136 m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN;
137 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
138 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
139 memset(m_macAddr, 0, MAC_ADDR_LENGTH);
140 m_lastDownEventId = 0;
141 m_pendingStatus = -1;
142 m_statusPollCount = 0;
143 m_operStatePollCount = 0;
144 m_requiredPollCount = 0; // Use system default
145 m_zoneUIN = zoneUIN;
146 m_isHidden = true;
147 m_pingTime = PING_TIME_TIMEOUT;
148 m_pingLastTimeStamp = 0;
149 m_ifTableSuffixLen = 0;
150 m_ifTableSuffix = NULL;
151 }
152
153 /**
154 * Interface class destructor
155 */
156 Interface::~Interface()
157 {
158 free(m_ifTableSuffix);
159 }
160
161 /**
162 * Returns last ping time
163 */
164 UINT32 Interface::getPingTime()
165 {
166 if ((time(NULL) - m_pingLastTimeStamp) > g_dwStatusPollingInterval)
167 {
168 updatePingData();
169 nxlog_debug(7, _T("Interface::getPingTime: update ping time is required! Last ping time %d."), m_pingLastTimeStamp);
170 }
171 return m_pingTime;
172 }
173
174 /**
175 * Create object from database record
176 */
177 bool Interface::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
178 {
179 bool bResult = false;
180
181 m_id = dwId;
182
183 if (!loadCommonProperties(hdb))
184 return false;
185
186 DB_STATEMENT hStmt = DBPrepare(hdb,
187 _T("SELECT if_type,if_index,node_id,")
188 _T("mac_addr,required_polls,bridge_port,phy_slot,")
189 _T("phy_port,peer_node_id,peer_if_id,description,")
190 _T("dot1x_pae_state,dot1x_backend_state,admin_state,")
191 _T("oper_state,peer_proto,alias,mtu,speed,parent_iface,")
192 _T("iftable_suffix FROM interfaces WHERE id=?"));
193 if (hStmt == NULL)
194 return false;
195 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
196
197 DB_RESULT hResult = DBSelectPrepared(hStmt);
198 if (hResult == NULL)
199 {
200 DBFreeStatement(hStmt);
201 return false; // Query failed
202 }
203
204 if (DBGetNumRows(hResult) != 0)
205 {
206 m_type = DBGetFieldULong(hResult, 0, 0);
207 m_index = DBGetFieldULong(hResult, 0, 1);
208 UINT32 nodeId = DBGetFieldULong(hResult, 0, 2);
209 DBGetFieldByteArray2(hResult, 0, 3, m_macAddr, MAC_ADDR_LENGTH, 0);
210 m_requiredPollCount = DBGetFieldLong(hResult, 0, 4);
211 m_bridgePortNumber = DBGetFieldULong(hResult, 0, 5);
212 m_slotNumber = DBGetFieldULong(hResult, 0, 6);
213 m_portNumber = DBGetFieldULong(hResult, 0, 7);
214 m_peerNodeId = DBGetFieldULong(hResult, 0, 8);
215 m_peerInterfaceId = DBGetFieldULong(hResult, 0, 9);
216 DBGetField(hResult, 0, 10, m_description, MAX_DB_STRING);
217 m_dot1xPaeAuthState = (WORD)DBGetFieldLong(hResult, 0, 11);
218 m_dot1xBackendAuthState = (WORD)DBGetFieldLong(hResult, 0, 12);
219 m_adminState = (WORD)DBGetFieldLong(hResult, 0, 13);
220 m_operState = (WORD)DBGetFieldLong(hResult, 0, 14);
221 m_confirmedOperState = m_operState;
222 m_peerDiscoveryProtocol = (LinkLayerProtocol)DBGetFieldLong(hResult, 0, 15);
223 DBGetField(hResult, 0, 16, m_alias, MAX_DB_STRING);
224 m_mtu = DBGetFieldULong(hResult, 0, 17);
225 m_speed = DBGetFieldUInt64(hResult, 0, 18);
226 m_parentInterfaceId = DBGetFieldULong(hResult, 0, 19);
227
228 TCHAR suffixText[128];
229 DBGetField(hResult, 0, 20, suffixText, 128);
230 StrStrip(suffixText);
231 if (suffixText[0] == 0)
232 {
233 UINT32 suffix[16];
234 size_t l = SNMPParseOID(suffixText, suffix, 16);
235 if (l > 0)
236 {
237 m_ifTableSuffixLen = (int)l;
238 m_ifTableSuffix = (UINT32 *)nx_memdup(suffix, l * sizeof(UINT32));
239 }
240 }
241
242 m_pingTime = PING_TIME_TIMEOUT;
243 m_pingLastTimeStamp = 0;
244
245 // Link interface to node
246 if (!m_isDeleted)
247 {
248 NetObj *object = FindObjectById(nodeId);
249 if (object == NULL)
250 {
251 nxlog_write(MSG_INVALID_NODE_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, nodeId);
252 }
253 else if (object->getObjectClass() != OBJECT_NODE)
254 {
255 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, nodeId);
256 }
257 else
258 {
259 object->addChild(this);
260 addParent(object);
261 m_zoneUIN = ((Node *)object)->getZoneUIN();
262 bResult = true;
263 }
264 }
265 else
266 {
267 bResult = true;
268 }
269 }
270
271 DBFreeResult(hResult);
272 DBFreeStatement(hStmt);
273
274 // Read IP addresses
275 hStmt = DBPrepare(hdb, _T("SELECT ip_addr,ip_netmask FROM interface_address_list WHERE iface_id = ?"));
276 if (hStmt != NULL)
277 {
278 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
279 hResult = DBSelectPrepared(hStmt);
280 if (hResult != NULL)
281 {
282 int count = DBGetNumRows(hResult);
283 for(int i = 0; i < count; i++)
284 {
285 InetAddress addr = DBGetFieldInetAddr(hResult, i, 0);
286 addr.setMaskBits(DBGetFieldLong(hResult, i, 1));
287 if (addr.isValid())
288 m_ipAddressList.add(addr);
289 }
290 DBFreeResult(hResult);
291 }
292 DBFreeStatement(hStmt);
293 }
294
295 // Load access list
296 loadACLFromDB(hdb);
297
298 // Validate loopback flag
299 if (m_type == IFTYPE_SOFTWARE_LOOPBACK)
300 {
301 m_flags |= IF_LOOPBACK;
302 }
303 else
304 {
305 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
306 int count = 0;
307 for(int i = 0; i < list->size(); i++)
308 {
309 if (list->get(i)->isLoopback())
310 count++;
311 }
312 if ((count > 0) && (count == list->size())) // all loopback addresses
313 m_flags |= IF_LOOPBACK;
314 else
315 m_flags &= ~IF_LOOPBACK;
316 }
317
318 return bResult;
319 }
320
321 /**
322 * Save interface object to database
323 */
324 bool Interface::saveToDatabase(DB_HANDLE hdb)
325 {
326 TCHAR szMacStr[16];
327 UINT32 dwNodeId;
328
329 lockProperties();
330
331 if (!saveCommonProperties(hdb))
332 {
333 unlockProperties();
334 return false;
335 }
336
337 // Determine owning node's ID
338 Node *pNode = getParentNode();
339 if (pNode != NULL)
340 dwNodeId = pNode->getId();
341 else
342 dwNodeId = 0;
343
344 // Form and execute INSERT or UPDATE query
345 DB_STATEMENT hStmt;
346 if (IsDatabaseRecordExist(hdb, _T("interfaces"), _T("id"), m_id))
347 {
348 hStmt = DBPrepare(hdb,
349 _T("UPDATE interfaces SET node_id=?,if_type=?,if_index=?,mac_addr=?,")
350 _T("required_polls=?,bridge_port=?,phy_slot=?,phy_port=?,")
351 _T("peer_node_id=?,peer_if_id=?,description=?,admin_state=?,")
352 _T("oper_state=?,dot1x_pae_state=?,dot1x_backend_state=?,")
353 _T("peer_proto=?,alias=?,mtu=?,speed=?,parent_iface=?,")
354 _T("iftable_suffix=? WHERE id=?"));
355 }
356 else
357 {
358 hStmt = DBPrepare(hdb,
359 _T("INSERT INTO interfaces (node_id,if_type,if_index,mac_addr,")
360 _T("required_polls,bridge_port,phy_slot,phy_port,peer_node_id,peer_if_id,description,")
361 _T("admin_state,oper_state,dot1x_pae_state,dot1x_backend_state,peer_proto,alias,mtu,speed,")
362 _T("parent_iface,iftable_suffix,id) ")
363 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
364 }
365 if (hStmt == NULL)
366 {
367 unlockProperties();
368 return FALSE;
369 }
370
371 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, dwNodeId);
372 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_type);
373 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, m_index);
374 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, BinToStr(m_macAddr, MAC_ADDR_LENGTH, szMacStr), DB_BIND_STATIC);
375 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_requiredPollCount);
376 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_bridgePortNumber);
377 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, m_slotNumber);
378 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, m_portNumber);
379 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, m_peerNodeId);
380 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, m_peerInterfaceId);
381 DBBind(hStmt, 11, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC);
382 DBBind(hStmt, 12, DB_SQLTYPE_INTEGER, (UINT32)m_adminState);
383 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, (UINT32)m_operState);
384 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (UINT32)m_dot1xPaeAuthState);
385 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (UINT32)m_dot1xBackendAuthState);
386 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, (INT32)m_peerDiscoveryProtocol);
387 DBBind(hStmt, 17, DB_SQLTYPE_VARCHAR, m_alias, DB_BIND_STATIC);
388 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, m_mtu);
389 DBBind(hStmt, 19, DB_SQLTYPE_BIGINT, m_speed);
390 DBBind(hStmt, 20, DB_SQLTYPE_INTEGER, m_parentInterfaceId);
391 if (m_ifTableSuffixLen > 0)
392 {
393 TCHAR buffer[128];
394 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, SNMPConvertOIDToText(m_ifTableSuffixLen, m_ifTableSuffix, buffer, 128), DB_BIND_TRANSIENT);
395 }
396 else
397 {
398 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, NULL, DB_BIND_STATIC);
399 }
400 DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, m_id);
401
402 bool success = DBExecute(hStmt);
403 DBFreeStatement(hStmt);
404
405 // Save IP addresses
406 if (success)
407 {
408 success = false;
409
410 hStmt = DBPrepare(hdb, _T("DELETE FROM interface_address_list WHERE iface_id = ?"));
411 if (hStmt != NULL)
412 {
413 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
414 success = DBExecute(hStmt);
415 DBFreeStatement(hStmt);
416 }
417 }
418
419 if (success && (m_ipAddressList.size() > 0))
420 {
421 hStmt = DBPrepare(hdb, _T("INSERT INTO interface_address_list (iface_id,ip_addr,ip_netmask) VALUES (?,?,?)"));
422 if (hStmt != NULL)
423 {
424 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
425 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
426 for(int i = 0; (i < list->size()) && success; i++)
427 {
428 InetAddress *a = list->get(i);
429 TCHAR buffer[64];
430 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, a->toString(buffer), DB_BIND_STATIC);
431 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, a->getMaskBits());
432 success = DBExecute(hStmt);
433 }
434 DBFreeStatement(hStmt);
435 }
436 else
437 {
438 success = false;
439 }
440 }
441
442 // Save access list
443 if (success)
444 success = saveACLToDB(hdb);
445
446 // Clear modifications flag and unlock object
447 if (success)
448 m_isModified = false;
449 unlockProperties();
450
451 return success;
452 }
453
454 /**
455 * Delete interface object from database
456 */
457 bool Interface::deleteFromDatabase(DB_HANDLE hdb)
458 {
459 bool success = NetObj::deleteFromDatabase(hdb);
460 if (success)
461 success = executeQueryOnObject(hdb, _T("DELETE FROM interfaces WHERE id=?"));
462 if (success)
463 success = executeQueryOnObject(hdb, _T("DELETE FROM interface_address_list WHERE iface_id=?"));
464 return success;
465 }
466
467 /**
468 * Perform status poll on interface
469 */
470 void Interface::statusPoll(ClientSession *session, UINT32 rqId, Queue *eventQueue, Cluster *cluster, SNMP_Transport *snmpTransport, UINT32 nodeIcmpProxy)
471 {
472 if (IsShutdownInProgress())
473 return;
474
475 m_pollRequestor = session;
476 Node *pNode = getParentNode();
477 if (pNode == NULL)
478 {
479 m_status = STATUS_UNKNOWN;
480 return; // Cannot find parent node, which is VERY strange
481 }
482
483 sendPollerMsg(rqId, _T(" Starting status poll on interface %s\r\n"), m_name);
484 sendPollerMsg(rqId, _T(" Current interface status is %s\r\n"), GetStatusAsText(m_status, true));
485
486 InterfaceAdminState adminState = IF_ADMIN_STATE_UNKNOWN;
487 InterfaceOperState operState = IF_OPER_STATE_UNKNOWN;
488 BOOL bNeedPoll = TRUE;
489
490 // Poll interface using different methods
491 if ((pNode->getCapabilities() & NC_IS_NATIVE_AGENT) &&
492 (!(pNode->getFlags() & NF_DISABLE_NXCP)) && (!(pNode->getState() & NSF_AGENT_UNREACHABLE)))
493 {
494 sendPollerMsg(rqId, _T(" Retrieving interface status from NetXMS agent\r\n"));
495 pNode->getInterfaceStatusFromAgent(m_index, &adminState, &operState);
496 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from NetXMS agent: adinState=%d operState=%d"), m_id, m_name, adminState, operState);
497 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
498 {
499 sendPollerMsg(rqId, POLLER_INFO _T(" Interface status retrieved from NetXMS agent\r\n"));
500 bNeedPoll = FALSE;
501 }
502 else
503 {
504 sendPollerMsg(rqId, POLLER_WARNING _T(" Unable to retrieve interface status from NetXMS agent\r\n"));
505 }
506 }
507
508 if (bNeedPoll && (pNode->getCapabilities() & NC_IS_SNMP) &&
509 (!(pNode->getFlags() & NF_DISABLE_SNMP)) && (!(pNode->getState() & NSF_SNMP_UNREACHABLE)) &&
510 (snmpTransport != NULL))
511 {
512 sendPollerMsg(rqId, _T(" Retrieving interface status from SNMP agent\r\n"));
513 pNode->getInterfaceStatusFromSNMP(snmpTransport, m_index, m_ifTableSuffixLen, m_ifTableSuffix, &adminState, &operState);
514 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from SNMP: adminState=%d operState=%d"), m_id, m_name, adminState, operState);
515 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
516 {
517 sendPollerMsg(rqId, POLLER_INFO _T(" Interface status retrieved from SNMP agent\r\n"));
518 bNeedPoll = FALSE;
519 }
520 else
521 {
522 sendPollerMsg(rqId, POLLER_WARNING _T(" Unable to retrieve interface status from SNMP agent\r\n"));
523 }
524 }
525
526 if (bNeedPoll)
527 {
528 // Ping cannot be used for cluster sync interfaces
529 if ((pNode->getFlags() & NF_DISABLE_ICMP) || isLoopback() || !m_ipAddressList.hasValidUnicastAddress())
530 {
531 // Interface doesn't have an IP address, so we can't ping it
532 sendPollerMsg(rqId, POLLER_WARNING _T(" Interface status cannot be determined\r\n"));
533 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot use ping for status check"), m_id, m_name);
534 }
535 else
536 {
537 icmpStatusPoll(rqId, nodeIcmpProxy, cluster, &adminState, &operState);
538 }
539 }
540
541 // Calculate interface object status based on admin state, oper state, and expected state
542 int oldStatus = m_status;
543 int newStatus;
544 int expectedState = (m_flags & IF_EXPECTED_STATE_MASK) >> 28;
545 switch(adminState)
546 {
547 case IF_ADMIN_STATE_UP:
548 case IF_ADMIN_STATE_UNKNOWN:
549 switch(operState)
550 {
551 case IF_OPER_STATE_UP:
552 if (expectedState == IF_EXPECTED_STATE_AUTO)
553 {
554 DbgPrintf(5, _T("Interface::StatusPoll(%d,%s): auto expected state changed to UP"), m_id, m_name);
555 expectedState = IF_EXPECTED_STATE_UP;
556 setExpectedState(expectedState);
557 }
558 newStatus = ((expectedState == IF_EXPECTED_STATE_DOWN) ? STATUS_CRITICAL : STATUS_NORMAL);
559 break;
560 case IF_OPER_STATE_DOWN:
561 if (expectedState == IF_EXPECTED_STATE_AUTO)
562 {
563 DbgPrintf(5, _T("Interface::StatusPoll(%d,%s): auto expected state changed to DOWN"), m_id, m_name);
564 expectedState = IF_EXPECTED_STATE_DOWN;
565 setExpectedState(expectedState);
566 }
567 newStatus = (expectedState == IF_EXPECTED_STATE_UP) ? STATUS_CRITICAL : STATUS_NORMAL;
568 break;
569 case IF_OPER_STATE_TESTING:
570 newStatus = STATUS_TESTING;
571 break;
572 case IF_OPER_STATE_DORMANT:
573 newStatus = (expectedState == IF_EXPECTED_STATE_UP) ? STATUS_MINOR : STATUS_NORMAL;
574 break;
575 case IF_OPER_STATE_NOT_PRESENT:
576 newStatus = STATUS_DISABLED;
577 break;
578 default:
579 newStatus = STATUS_UNKNOWN;
580 break;
581 }
582 break;
583 case IF_ADMIN_STATE_DOWN:
584 if (expectedState == IF_EXPECTED_STATE_AUTO)
585 {
586 DbgPrintf(5, _T("Interface::StatusPoll(%d,%s): auto expected state changed to DOWN"), m_id, m_name);
587 expectedState = IF_EXPECTED_STATE_DOWN;
588 setExpectedState(expectedState);
589 }
590 newStatus = STATUS_DISABLED;
591 break;
592 case IF_ADMIN_STATE_TESTING:
593 newStatus = STATUS_TESTING;
594 break;
595 default:
596 newStatus = STATUS_UNKNOWN;
597 break;
598 }
599
600 // Check 802.1x state
601 if ((pNode->getCapabilities() & NC_IS_8021X) && isPhysicalPort() && (snmpTransport != NULL))
602 {
603 DbgPrintf(5, _T("StatusPoll(%s): Checking 802.1x state for interface %s"), pNode->getName(), m_name);
604 paeStatusPoll(rqId, snmpTransport, pNode);
605 if ((m_dot1xPaeAuthState == PAE_STATE_FORCE_UNAUTH) && (newStatus < STATUS_MAJOR))
606 newStatus = STATUS_MAJOR;
607 }
608
609 // Reset status to unknown if node has known network connectivity problems
610 if ((newStatus == STATUS_CRITICAL) && (pNode->getState() & DCSF_NETWORK_PATH_PROBLEM))
611 {
612 newStatus = STATUS_UNKNOWN;
613 DbgPrintf(6, _T("StatusPoll(%s): Status for interface %s reset to UNKNOWN"), pNode->getName(), m_name);
614 }
615
616 if (newStatus == m_pendingStatus)
617 {
618 m_statusPollCount++;
619 }
620 else
621 {
622 m_pendingStatus = newStatus;
623 m_statusPollCount = 1;
624 }
625
626 if (operState == m_pendingOperState)
627 {
628 m_operStatePollCount++;
629 }
630 else
631 {
632 m_pendingOperState = operState;
633 m_operStatePollCount = 1;
634 }
635
636 int requiredPolls = (m_requiredPollCount > 0) ? m_requiredPollCount :
637 ((getParentNode()->getRequiredPolls() > 0) ? getParentNode()->getRequiredPolls() : g_requiredPolls);
638 sendPollerMsg(rqId, _T(" Interface is %s for %d poll%s (%d poll%s required for status change)\r\n"),
639 GetStatusAsText(newStatus, true), m_statusPollCount, (m_statusPollCount == 1) ? _T("") : _T("s"),
640 requiredPolls, (requiredPolls == 1) ? _T("") : _T("s"));
641 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): newStatus=%d oldStatus=%d pollCount=%d requiredPolls=%d"),
642 m_id, m_name, newStatus, oldStatus, m_statusPollCount, requiredPolls);
643
644 if ((operState != m_confirmedOperState) && (m_operStatePollCount >= requiredPolls))
645 {
646 DbgPrintf(6, _T("Interface::StatusPoll(%d,%s): confirmedOperState=%d pollCount=%d requiredPolls=%d"),
647 m_id, m_name, (int)operState, m_operStatePollCount, requiredPolls);
648 m_confirmedOperState = operState;
649 }
650
651 if ((newStatus != oldStatus) && (m_statusPollCount >= requiredPolls) && (expectedState != IF_EXPECTED_STATE_IGNORE))
652 {
653 static UINT32 statusToEvent[] =
654 {
655 EVENT_INTERFACE_UP, // Normal
656 EVENT_INTERFACE_UP, // Warning
657 EVENT_INTERFACE_UP, // Minor
658 EVENT_INTERFACE_DOWN, // Major
659 EVENT_INTERFACE_DOWN, // Critical
660 EVENT_INTERFACE_UNKNOWN, // Unknown
661 EVENT_INTERFACE_UNKNOWN, // Unmanaged
662 EVENT_INTERFACE_DISABLED, // Disabled
663 EVENT_INTERFACE_TESTING // Testing
664 };
665 static UINT32 statusToEventInverted[] =
666 {
667 EVENT_INTERFACE_EXPECTED_DOWN, // Normal
668 EVENT_INTERFACE_EXPECTED_DOWN, // Warning
669 EVENT_INTERFACE_EXPECTED_DOWN, // Minor
670 EVENT_INTERFACE_UNEXPECTED_UP, // Major
671 EVENT_INTERFACE_UNEXPECTED_UP, // Critical
672 EVENT_INTERFACE_UNKNOWN, // Unknown
673 EVENT_INTERFACE_UNKNOWN, // Unmanaged
674 EVENT_INTERFACE_DISABLED, // Disabled
675 EVENT_INTERFACE_TESTING // Testing
676 };
677
678 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): status changed from %d to %d"), m_id, m_name, m_status, newStatus);
679 m_status = newStatus;
680 m_pendingStatus = -1; // Invalidate pending status
681 if (!m_isSystem)
682 {
683 sendPollerMsg(rqId, _T(" Interface status changed to %s\r\n"), GetStatusAsText(m_status, true));
684 const InetAddress& addr = m_ipAddressList.getFirstUnicastAddress();
685 PostEventEx(eventQueue,
686 (expectedState == IF_EXPECTED_STATE_DOWN) ? statusToEventInverted[m_status] : statusToEvent[m_status],
687 pNode->getId(), "dsAdd", m_id, m_name, &addr, addr.getMaskBits(), m_index);
688 }
689 }
690 else if (expectedState == IF_EXPECTED_STATE_IGNORE)
691 {
692 m_status = (newStatus <= STATUS_CRITICAL) ? STATUS_NORMAL : newStatus;
693 if (m_status != oldStatus)
694 m_pendingStatus = -1; // Invalidate pending status
695 }
696
697 lockProperties();
698 if ((m_status != oldStatus) || (adminState != (int)m_adminState) || (operState != (int)m_operState))
699 {
700 m_adminState = (WORD)adminState;
701 m_operState = (WORD)operState;
702 setModified();
703 }
704 unlockProperties();
705
706 sendPollerMsg(rqId, _T(" Interface status after poll is %s\r\n"), GetStatusAsText(m_status, true));
707 sendPollerMsg(rqId, _T(" Finished status poll on interface %s\r\n"), m_name);
708 }
709
710 /**
711 * Updates last ping time and ping time
712 */
713 void Interface::updatePingData()
714 {
715 Node *pNode = getParentNode();
716 if (pNode == NULL)
717 {
718 nxlog_debug(7, _T("Interface::updatePingData: Can't find parent node"));
719 return;
720 }
721 UINT32 icmpProxy = pNode->getIcmpProxy();
722
723 if (IsZoningEnabled() && (m_zoneUIN != 0) && (icmpProxy == 0))
724 {
725 Zone *zone = FindZoneByUIN(m_zoneUIN);
726 if (zone != NULL)
727 {
728 icmpProxy = zone->getProxyNodeId();
729 }
730 }
731
732 if (icmpProxy != 0)
733 {
734 nxlog_debug(7, _T("Interface::updatePingData: ping via proxy [%u]"), icmpProxy);
735 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
736 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
737 {
738 nxlog_debug(7, _T("Interface::updatePingData: proxy node found: %s"), proxyNode->getName());
739 AgentConnection *conn = proxyNode->createAgentConnection();
740 if (conn != NULL)
741 {
742 TCHAR parameter[128], buffer[64];
743 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
744 long value = -1;
745 for(int i = 0; (i < list->size()) && ((value == 10000) || (value == -1)); i++)
746 {
747 const InetAddress *a = list->get(i);
748 _sntprintf(parameter, 128, _T("Icmp.Ping(%s)"), a->toString(buffer));
749 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
750 {
751 nxlog_debug(7, _T("Interface::updatePingData: proxy response: \"%s\""), buffer);
752 TCHAR *eptr;
753 value = _tcstol(buffer, &eptr, 10);
754 if (*eptr != 0)
755 {
756 value = -1;
757 }
758 }
759 }
760
761 if (value >= 0)
762 {
763 m_pingTime = value;
764 }
765 else
766 {
767 m_pingTime = PING_TIME_TIMEOUT;
768 nxlog_debug(7, _T("Interface::updatePingData: incorrect value or error while parsing"));
769 }
770 m_pingLastTimeStamp = time(NULL);
771 conn->decRefCount();
772 }
773 else
774 {
775 nxlog_debug(7, _T("Interface::updatePingData: cannot connect to agent on proxy node [%u]"), icmpProxy);
776 m_pingTime = PING_TIME_TIMEOUT;
777 }
778 }
779 else
780 {
781 nxlog_debug(7, _T("Interface::updatePingData: proxy node not available [%u]"), icmpProxy);
782 m_pingTime = PING_TIME_TIMEOUT;
783 }
784 }
785 else // not using ICMP proxy
786 {
787 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
788 UINT32 dwPingStatus = ICMP_TIMEOUT;
789 for(int i = 0; (i < list->size()) && (dwPingStatus != ICMP_SUCCESS); i++)
790 {
791 const InetAddress *a = list->get(i);
792 nxlog_debug(7, _T("Interface::StatusPoll(%d,%s): calling IcmpPing(%s,3,%d,%d,%d)"),
793 m_id, m_name, (const TCHAR *)a->toString(), g_icmpPingTimeout, m_pingTime, g_icmpPingSize);
794 dwPingStatus = IcmpPing(*a, 3, g_icmpPingTimeout, &m_pingTime, g_icmpPingSize);
795 }
796 if (dwPingStatus != ICMP_SUCCESS)
797 {
798 nxlog_debug(7, _T("Interface::updatePingData: error: %d"), dwPingStatus);
799 m_pingTime = PING_TIME_TIMEOUT;
800 }
801 m_pingLastTimeStamp = time(NULL);
802 }
803 }
804
805 /**
806 * Do ICMP part of status poll
807 */
808 void Interface::icmpStatusPoll(UINT32 rqId, UINT32 nodeIcmpProxy, Cluster *cluster, InterfaceAdminState *adminState, InterfaceOperState *operState)
809 {
810 // Use ICMP ping as a last option
811 UINT32 icmpProxy = nodeIcmpProxy;
812
813 if (IsZoningEnabled() && (m_zoneUIN != 0) && (icmpProxy == 0))
814 {
815 Zone *zone = FindZoneByUIN(m_zoneUIN);
816 if (zone != NULL)
817 {
818 icmpProxy = zone->getProxyNodeId();
819 }
820 }
821
822 if (icmpProxy != 0)
823 {
824 sendPollerMsg(rqId, _T(" Starting ICMP ping via proxy\r\n"));
825 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping via proxy [%u]"), m_id, m_name, icmpProxy);
826 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
827 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
828 {
829 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node found: %s"), m_id, m_name, proxyNode->getName());
830 AgentConnection *conn = proxyNode->createAgentConnection();
831 if (conn != NULL)
832 {
833 TCHAR parameter[128], buffer[64];
834 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
835 long value = -1;
836 for(int i = 0; (i < list->size()) && ((value == 10000) || (value == -1)); i++)
837 {
838 const InetAddress *a = list->get(i);
839 if (a->isValidUnicast() && ((cluster == NULL) || !cluster->isSyncAddr(*a)))
840 {
841 _sntprintf(parameter, 128, _T("Icmp.Ping(%s)"), a->toString(buffer));
842 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
843 {
844 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy response: \"%s\""), m_id, m_name, buffer);
845 TCHAR *eptr;
846 value = _tcstol(buffer, &eptr, 10);
847 if (*eptr != 0)
848 {
849 value = -1;
850 }
851 }
852 }
853 }
854
855 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): response time %d"), m_id, m_name, (int)value);
856 if (value >= 0)
857 {
858 m_pingTime = (UINT32)value;
859 if (value < 10000)
860 {
861 *adminState = IF_ADMIN_STATE_UP;
862 *operState = IF_OPER_STATE_UP;
863 }
864 else
865 {
866 *adminState = IF_ADMIN_STATE_UNKNOWN;
867 *operState = IF_OPER_STATE_DOWN;
868 }
869 }
870 m_pingLastTimeStamp = time(NULL);
871 conn->decRefCount();
872 }
873 else
874 {
875 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot connect to agent on proxy node"), m_id, m_name);
876 sendPollerMsg(rqId, POLLER_ERROR _T(" Unable to establish connection with proxy node\r\n"));
877 }
878 }
879 else
880 {
881 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node not available"), m_id, m_name);
882 sendPollerMsg(rqId, POLLER_ERROR _T(" ICMP proxy not available\r\n"));
883 }
884 }
885 else // not using ICMP proxy
886 {
887 sendPollerMsg(rqId, _T(" Starting ICMP ping\r\n"));
888 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
889 UINT32 dwPingStatus = ICMP_TIMEOUT;
890 for(int i = 0; (i < list->size()) && (dwPingStatus != ICMP_SUCCESS); i++)
891 {
892 const InetAddress *a = list->get(i);
893 if (a->isValidUnicast() && ((cluster == NULL) || !cluster->isSyncAddr(*a)))
894 {
895 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): calling IcmpPing(%s,3,%d,%d,%d)"),
896 m_id, m_name, (const TCHAR *)a->toString(), g_icmpPingTimeout, m_pingTime, g_icmpPingSize);
897 dwPingStatus = IcmpPing(*a, 3, g_icmpPingTimeout, &m_pingTime, g_icmpPingSize);
898 }
899 }
900 m_pingLastTimeStamp = time(NULL);
901 if (dwPingStatus == ICMP_SUCCESS)
902 {
903 *adminState = IF_ADMIN_STATE_UP;
904 *operState = IF_OPER_STATE_UP;
905 }
906 else
907 {
908 m_pingTime = PING_TIME_TIMEOUT;
909 *adminState = IF_ADMIN_STATE_UNKNOWN;
910 *operState = IF_OPER_STATE_DOWN;
911 }
912 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping result %d, adminState=%d, operState=%d"), m_id, m_name, dwPingStatus, *adminState, *operState);
913 }
914 }
915
916 /**
917 * PAE (802.1x) status poll
918 */
919 void Interface::paeStatusPoll(UINT32 rqId, SNMP_Transport *pTransport, Node *node)
920 {
921 static const TCHAR *paeStateText[] =
922 {
923 _T("UNKNOWN"),
924 _T("INITIALIZE"),
925 _T("DISCONNECTED"),
926 _T("CONNECTING"),
927 _T("AUTHENTICATING"),
928 _T("AUTHENTICATED"),
929 _T("ABORTING"),
930 _T("HELD"),
931 _T("FORCE AUTH"),
932 _T("FORCE UNAUTH"),
933 _T("RESTART")
934 };
935 static const TCHAR *backendStateText[] =
936 {
937 _T("UNKNOWN"),
938 _T("REQUEST"),
939 _T("RESPONSE"),
940 _T("SUCCESS"),
941 _T("FAIL"),
942 _T("TIMEOUT"),
943 _T("IDLE"),
944 _T("INITIALIZE"),
945 _T("IGNORE")
946 };
947 #define PAE_STATE_TEXT(x) ((((int)(x) <= PAE_STATE_RESTART) && ((int)(x) >= 0)) ? paeStateText[(int)(x)] : paeStateText[0])
948 #define BACKEND_STATE_TEXT(x) ((((int)(x) <= BACKEND_STATE_IGNORE) && ((int)(x) >= 0)) ? backendStateText[(int)(x)] : backendStateText[0])
949
950 sendPollerMsg(rqId, _T(" Checking port 802.1x status...\r\n"));
951
952 TCHAR oid[256];
953 INT32 paeState = PAE_STATE_UNKNOWN, backendState = BACKEND_STATE_UNKNOWN;
954 bool modified = false;
955
956 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.1.%d"), m_index);
957 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &paeState, sizeof(INT32), 0);
958
959 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.2.%d"), m_index);
960 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &backendState, sizeof(INT32), 0);
961
962 if (m_dot1xPaeAuthState != (WORD)paeState)
963 {
964 sendPollerMsg(rqId, _T(" Port PAE state changed to %s\r\n"), PAE_STATE_TEXT(paeState));
965 modified = true;
966 if (!m_isSystem)
967 {
968 PostEvent(EVENT_8021X_PAE_STATE_CHANGED, node->getId(), "dsdsds", paeState, PAE_STATE_TEXT(paeState),
969 (UINT32)m_dot1xPaeAuthState, PAE_STATE_TEXT(m_dot1xPaeAuthState), m_id, m_name);
970
971 if (paeState == PAE_STATE_FORCE_UNAUTH)
972 {
973 PostEvent(EVENT_8021X_PAE_FORCE_UNAUTH, node->getId(), "ds", m_id, m_name);
974 }
975 }
976 }
977
978 if (m_dot1xBackendAuthState != (WORD)backendState)
979 {
980 sendPollerMsg(rqId, _T(" Port backend state changed to %s\r\n"), BACKEND_STATE_TEXT(backendState));
981 modified = true;
982 if (!m_isSystem)
983 {
984 PostEvent(EVENT_8021X_BACKEND_STATE_CHANGED, node->getId(), "dsdsds", backendState, BACKEND_STATE_TEXT(backendState),
985 (UINT32)m_dot1xBackendAuthState, BACKEND_STATE_TEXT(m_dot1xBackendAuthState), m_id, m_name);
986
987 if (backendState == BACKEND_STATE_FAIL)
988 {
989 PostEvent(EVENT_8021X_AUTH_FAILED, node->getId(), "ds", m_id, m_name);
990 }
991 else if (backendState == BACKEND_STATE_TIMEOUT)
992 {
993 PostEvent(EVENT_8021X_AUTH_TIMEOUT, node->getId(), "ds", m_id, m_name);
994 }
995 }
996 }
997
998 if (modified)
999 {
1000 lockProperties();
1001 m_dot1xPaeAuthState = (WORD)paeState;
1002 m_dot1xBackendAuthState = (WORD)backendState;
1003 setModified();
1004 unlockProperties();
1005 }
1006 }
1007
1008 /**
1009 * Create NXCP message with object's data
1010 */
1011 void Interface::fillMessageInternal(NXCPMessage *pMsg)
1012 {
1013 NetObj::fillMessageInternal(pMsg);
1014
1015 m_ipAddressList.fillMessage(pMsg, VID_IP_ADDRESS_COUNT, VID_IP_ADDRESS_LIST_BASE);
1016 pMsg->setField(VID_IF_INDEX, m_index);
1017 pMsg->setField(VID_IF_TYPE, m_type);
1018 pMsg->setField(VID_MTU, m_mtu);
1019 pMsg->setField(VID_SPEED, m_speed);
1020 pMsg->setField(VID_IF_SLOT, m_slotNumber);
1021 pMsg->setField(VID_IF_PORT, m_portNumber);
1022 pMsg->setField(VID_MAC_ADDR, m_macAddr, MAC_ADDR_LENGTH);
1023 pMsg->setField(VID_REQUIRED_POLLS, (WORD)m_requiredPollCount);
1024 pMsg->setField(VID_PEER_NODE_ID, m_peerNodeId);
1025 pMsg->setField(VID_PEER_INTERFACE_ID, m_peerInterfaceId);
1026 pMsg->setField(VID_PEER_PROTOCOL, (INT16)m_peerDiscoveryProtocol);
1027 pMsg->setField(VID_DESCRIPTION, m_description);
1028 pMsg->setField(VID_ALIAS, m_alias);
1029 pMsg->setField(VID_ADMIN_STATE, m_adminState);
1030 pMsg->setField(VID_OPER_STATE, m_operState);
1031 pMsg->setField(VID_DOT1X_PAE_STATE, m_dot1xPaeAuthState);
1032 pMsg->setField(VID_DOT1X_BACKEND_STATE, m_dot1xBackendAuthState);
1033 pMsg->setField(VID_ZONE_UIN, m_zoneUIN);
1034 pMsg->setFieldFromInt32Array(VID_IFTABLE_SUFFIX, m_ifTableSuffixLen, m_ifTableSuffix);
1035 pMsg->setField(VID_PARENT_INTERFACE, m_parentInterfaceId);
1036 }
1037
1038 /**
1039 * Modify object from message
1040 */
1041 UINT32 Interface::modifyFromMessageInternal(NXCPMessage *pRequest)
1042 {
1043 // Flags
1044 if (pRequest->isFieldExist(VID_FLAGS))
1045 {
1046 UINT32 mask = pRequest->isFieldExist(VID_FLAGS_MASK) ? (pRequest->getFieldAsUInt32(VID_FLAGS_MASK) & IF_USER_FLAGS_MASK) : IF_USER_FLAGS_MASK;
1047 m_flags &= ~mask;
1048 m_flags |= pRequest->getFieldAsUInt32(VID_FLAGS) & mask;
1049 }
1050
1051 // Number of required polls
1052 if (pRequest->isFieldExist(VID_REQUIRED_POLLS))
1053 m_requiredPollCount = (int)pRequest->getFieldAsUInt16(VID_REQUIRED_POLLS);
1054
1055 // Expected interface state
1056 if (pRequest->isFieldExist(VID_EXPECTED_STATE))
1057 {
1058 setExpectedStateInternal(pRequest->getFieldAsInt16(VID_EXPECTED_STATE));
1059 }
1060
1061 return NetObj::modifyFromMessageInternal(pRequest);
1062 }
1063
1064 /**
1065 * Set expected state for interface
1066 */
1067 void Interface::setExpectedStateInternal(int state)
1068 {
1069 static UINT32 eventCode[] = { EVENT_IF_EXPECTED_STATE_UP, EVENT_IF_EXPECTED_STATE_DOWN, EVENT_IF_EXPECTED_STATE_IGNORE };
1070
1071 int curr = (m_flags & IF_EXPECTED_STATE_MASK) >> 28;
1072 if (curr != state)
1073 {
1074 m_flags &= ~IF_EXPECTED_STATE_MASK;
1075 m_flags |= (UINT32)state << 28;
1076 setModified();
1077 if (state != IF_EXPECTED_STATE_AUTO)
1078 PostEvent(eventCode[state], getParentNodeId(), "ds", m_index, m_name);
1079 }
1080 }
1081
1082 /**
1083 * Set "exclude from topology" flag
1084 */
1085 void Interface::setExcludeFromTopology(bool excluded)
1086 {
1087 lockProperties();
1088 if (excluded)
1089 m_flags |= IF_EXCLUDE_FROM_TOPOLOGY;
1090 else
1091 m_flags &= ~IF_EXCLUDE_FROM_TOPOLOGY;
1092 setModified();
1093 unlockProperties();
1094 }
1095
1096 /**
1097 * Wake up node bound to this interface by sending magic packet
1098 */
1099 UINT32 Interface::wakeUp()
1100 {
1101 UINT32 rcc = RCC_NO_MAC_ADDRESS;
1102
1103 if (memcmp(m_macAddr, "\x00\x00\x00\x00\x00\x00", 6))
1104 {
1105 const InetAddress addr = m_ipAddressList.getFirstUnicastAddressV4();
1106 if (addr.isValid())
1107 {
1108 UINT32 destAddr = htonl(addr.getAddressV4() | ~(0xFFFFFFFF << (32 - addr.getMaskBits())));
1109 if (SendMagicPacket(destAddr, m_macAddr, 5))
1110 rcc = RCC_SUCCESS;
1111 else
1112 rcc = RCC_COMM_FAILURE;
1113 }
1114 }
1115 return rcc;
1116 }
1117
1118 /**
1119 * Get interface's parent node
1120 */
1121 Node *Interface::getParentNode()
1122 {
1123 Node *pNode = NULL;
1124
1125 lockParentList(false);
1126 for(int i = 0; i < m_parentList->size(); i++)
1127 if (m_parentList->get(i)->getObjectClass() == OBJECT_NODE)
1128 {
1129 pNode = (Node *)m_parentList->get(i);
1130 break;
1131 }
1132 unlockParentList();
1133 return pNode;
1134 }
1135
1136 /**
1137 * Get ID of parent node object
1138 */
1139 UINT32 Interface::getParentNodeId()
1140 {
1141 Node *node = getParentNode();
1142 return (node != NULL) ? node->getId() : 0;
1143 }
1144
1145 /**
1146 * Update zone ID. New zone ID taken from parent node.
1147 */
1148 void Interface::updateZoneUIN()
1149 {
1150 Node *node = getParentNode();
1151 if (node != NULL)
1152 {
1153 // Unregister from old zone
1154 Zone *zone = FindZoneByUIN(m_zoneUIN);
1155 if (zone != NULL)
1156 zone->removeFromIndex(this);
1157
1158 lockProperties();
1159 m_zoneUIN = node->getZoneUIN();
1160 setModified();
1161 unlockProperties();
1162
1163 // Register in new zone
1164 zone = FindZoneByUIN(m_zoneUIN);
1165 if (zone != NULL)
1166 zone->addToIndex(this);
1167 }
1168 }
1169
1170 /**
1171 * Handler for object deletion notification
1172 */
1173 void Interface::onObjectDelete(UINT32 dwObjectId)
1174 {
1175 if ((m_peerNodeId == dwObjectId) || (m_peerInterfaceId == dwObjectId))
1176 {
1177 lockProperties();
1178 m_peerNodeId = 0;
1179 m_peerInterfaceId = 0;
1180 setModified();
1181 unlockProperties();
1182 }
1183 NetObj::onObjectDelete(dwObjectId);
1184 }
1185
1186 /**
1187 * Set peer information
1188 */
1189 void Interface::setPeer(Node *node, Interface *iface, LinkLayerProtocol protocol, bool reflection)
1190 {
1191 if ((m_peerNodeId == node->getId()) && (m_peerInterfaceId == iface->getId()) && (m_peerDiscoveryProtocol == protocol))
1192 {
1193 if ((m_flags & IF_PEER_REFLECTION) && !reflection)
1194 {
1195 // set peer information as confirmed
1196 m_flags &= ~IF_PEER_REFLECTION;
1197 setModified();
1198 }
1199 return;
1200 }
1201
1202 m_peerNodeId = node->getId();
1203 m_peerInterfaceId = iface->getId();
1204 m_peerDiscoveryProtocol = protocol;
1205 if (reflection)
1206 m_flags |= IF_PEER_REFLECTION;
1207 else
1208 m_flags &= ~IF_PEER_REFLECTION;
1209 setModified();
1210 if (!m_isSystem)
1211 {
1212 static const TCHAR *names[] = { _T("localIfId"), _T("localIfIndex"), _T("localIfName"),
1213 _T("localIfIP"), _T("localIfMAC"), _T("remoteNodeId"), _T("remoteNodeName"),
1214 _T("remoteIfId"), _T("remoteIfIndex"), _T("remoteIfName"), _T("remoteIfIP"),
1215 _T("remoteIfMAC"), _T("protocol") };
1216 PostEventWithNames(EVENT_IF_PEER_CHANGED, getParentNodeId(), "ddsAhdsddsAhd", names,
1217 m_id, m_index, m_name, &m_ipAddressList.getFirstUnicastAddress(), m_macAddr,
1218 node->getId(), node->getName(), iface->getId(), iface->getIfIndex(), iface->getName(),
1219 &iface->getIpAddressList()->getFirstUnicastAddress(), iface->getMacAddr(), protocol);
1220 }
1221 }
1222
1223 /**
1224 * Set MAC address for interface
1225 */
1226 void Interface::setMacAddr(const BYTE *macAddr, bool updateMacDB)
1227 {
1228 lockProperties();
1229 if (updateMacDB)
1230 MacDbRemove(m_macAddr);
1231 memcpy(m_macAddr, macAddr, MAC_ADDR_LENGTH);
1232 if (updateMacDB)
1233 MacDbAddInterface(this);
1234 setModified();
1235 unlockProperties();
1236 }
1237
1238 /**
1239 * Set IP address (should be used only for fake interfaces with single IP)
1240 */
1241 void Interface::setIpAddress(const InetAddress& addr)
1242 {
1243 lockProperties();
1244 if (m_ipAddressList.size() == 1)
1245 {
1246 UpdateInterfaceIndex(m_ipAddressList.get(0), addr, this);
1247 m_ipAddressList.clear();
1248 m_ipAddressList.add(addr);
1249 setModified();
1250 }
1251 unlockProperties();
1252 }
1253
1254 /**
1255 * Get first usable IP address
1256 */
1257 const InetAddress& Interface::getFirstIpAddress()
1258 {
1259 const InetAddress& a = m_ipAddressList.getFirstUnicastAddress();
1260 return a.isValid() ? a : m_ipAddressList.get(0);
1261 }
1262
1263 /**
1264 * Add IP address
1265 */
1266 void Interface::addIpAddress(const InetAddress& addr)
1267 {
1268 lockProperties();
1269 m_ipAddressList.add(addr);
1270 setModified();
1271 unlockProperties();
1272 if (!isExcludedFromTopology())
1273 {
1274 if (IsZoningEnabled())
1275 {
1276 Zone *zone = FindZoneByUIN(m_zoneUIN);
1277 if (zone != NULL)
1278 {
1279 zone->addToIndex(addr, this);
1280 }
1281 else
1282 {
1283 DbgPrintf(2, _T("Cannot find zone object with GUID=%d for interface object %s [%d]"), (int)m_zoneUIN, m_name, (int)m_id);
1284 }
1285 }
1286 else
1287 {
1288 g_idxInterfaceByAddr.put(addr, this);
1289 }
1290 }
1291 }
1292
1293 /**
1294 * Delete IP address
1295 */
1296 void Interface::deleteIpAddress(InetAddress addr)
1297 {
1298 lockProperties();
1299 m_ipAddressList.remove(addr);
1300 setModified();
1301 unlockProperties();
1302 if (!isExcludedFromTopology())
1303 {
1304 if (IsZoningEnabled())
1305 {
1306 Zone *zone = FindZoneByUIN(m_zoneUIN);
1307 if (zone != NULL)
1308 {
1309 zone->removeFromInterfaceIndex(addr);
1310 }
1311 else
1312 {
1313 DbgPrintf(2, _T("Cannot find zone object with GUID=%d for interface object %s [%d]"), (int)m_zoneUIN, m_name, (int)m_id);
1314 }
1315 }
1316 else
1317 {
1318 g_idxInterfaceByAddr.remove(addr);
1319 }
1320 }
1321 }
1322
1323 /**
1324 * Change network mask for IP address
1325 */
1326 void Interface::setNetMask(const InetAddress& addr)
1327 {
1328 lockProperties();
1329 m_ipAddressList.replace(addr);
1330 setModified();
1331 unlockProperties();
1332 }
1333
1334 /**
1335 * Create NXSL object for this object
1336 */
1337 NXSL_Value *Interface::createNXSLObject()
1338 {
1339 return new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, this));
1340 }
1341
1342 /**
1343 * Serialize object to JSON
1344 */
1345 json_t *Interface::toJson()
1346 {
1347 json_t *root = NetObj::toJson();
1348 json_object_set_new(root, "index", json_integer(m_index));
1349 char macAddrText[64];
1350 json_object_set_new(root, "macAddr", json_string(BinToStrA(m_macAddr, MAC_ADDR_LENGTH, macAddrText)));
1351 json_object_set_new(root, "ipAddressList", m_ipAddressList.toJson());
1352 json_object_set_new(root, "flags", json_integer(m_flags));
1353 json_object_set_new(root, "description", json_string_t(m_description));
1354 json_object_set_new(root, "alias", json_string_t(m_alias));
1355 json_object_set_new(root, "type", json_integer(m_type));
1356 json_object_set_new(root, "mtu", json_integer(m_mtu));
1357 json_object_set_new(root, "speed", json_integer(m_speed));
1358 json_object_set_new(root, "bridgePortNumber", json_integer(m_bridgePortNumber));
1359 json_object_set_new(root, "slotNumber", json_integer(m_slotNumber));
1360 json_object_set_new(root, "portNumber", json_integer(m_portNumber));
1361 json_object_set_new(root, "peerNodeId", json_integer(m_peerNodeId));
1362 json_object_set_new(root, "peerInterfaceId", json_integer(m_peerInterfaceId));
1363 json_object_set_new(root, "peerDiscoveryProtocol", json_integer(m_peerDiscoveryProtocol));
1364 json_object_set_new(root, "adminState", json_integer(m_adminState));
1365 json_object_set_new(root, "operState", json_integer(m_operState));
1366 json_object_set_new(root, "pendingOperState", json_integer(m_pendingOperState));
1367 json_object_set_new(root, "confirmedOperState", json_integer(m_confirmedOperState));
1368 json_object_set_new(root, "dot1xPaeAuthState", json_integer(m_dot1xPaeAuthState));
1369 json_object_set_new(root, "dot1xBackendAuthState", json_integer(m_dot1xBackendAuthState));
1370 json_object_set_new(root, "lastDownEventId", json_integer(m_lastDownEventId));
1371 json_object_set_new(root, "pendingStatus", json_integer(m_pendingStatus));
1372 json_object_set_new(root, "statusPollCount", json_integer(m_statusPollCount));
1373 json_object_set_new(root, "operStatePollCount", json_integer(m_operStatePollCount));
1374 json_object_set_new(root, "requiredPollCount", json_integer(m_requiredPollCount));
1375 json_object_set_new(root, "zoneUIN", json_integer(m_zoneUIN));
1376 json_object_set_new(root, "pingTime", json_integer(m_pingTime));
1377 json_object_set_new(root, "pingLastTimeStamp", json_integer(m_pingLastTimeStamp));
1378 json_object_set_new(root, "ifTableSuffixLen", json_integer(m_ifTableSuffixLen));
1379 json_object_set_new(root, "ifTableSuffix", json_integer_array(m_ifTableSuffix, m_ifTableSuffixLen));
1380 return root;
1381 }