added access point status polls (currently for IP connected APs only)
authorVictor Kirhenshtein <victor@netxms.org>
Wed, 14 May 2014 11:13:49 +0000 (14:13 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Wed, 14 May 2014 11:13:49 +0000 (14:13 +0300)
14 files changed:
include/netxmsdb.h
include/nxevent.h
sql/events.in
src/server/core/accesspoint.cpp
src/server/core/node.cpp
src/server/drivers/airespace/airespace.cpp
src/server/drivers/mikrotik/mikrotik.cpp
src/server/drivers/ntws/ntws.cpp
src/server/drivers/ntws/ntws.vcproj
src/server/drivers/symbol-ws/symbol-ws.cpp
src/server/include/nddrv.h
src/server/include/nms_objects.h
src/server/libnxsrv/ndd.cpp
src/server/tools/nxdbmgr/upgrade.cpp

index 0005629..98e7ed4 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxmsdb_h
 #define _netxmsdb_h
 
-#define DB_FORMAT_VERSION   317
+#define DB_FORMAT_VERSION   318
 
 #endif
index 6d2dfe8..23d6fc9 100644 (file)
 #define EVENT_IF_PEER_CHANGED             71
 #define EVENT_AP_ADOPTED                  72
 #define EVENT_AP_UNADOPTED                73
+#define EVENT_AP_DOWN                     74
 
 #define EVENT_SNMP_UNMATCHED_TRAP         500
 #define EVENT_SNMP_COLD_START             501
index 0578d22..e8b66f3 100644 (file)
@@ -851,6 +851,21 @@ INSERT INTO event_cfg (event_code,event_name,severity,flags,message,description)
                '    6) Access point model' CONCAT CRLF CONCAT
                '    7) Access point serial number'
        );
+INSERT INTO event_cfg (event_code,event_name,severity,flags,message,description) VALUES
+       (
+               EVENT_AP_DOWN, 'SYS_AP_DOWN',
+               EVENT_SEVERITY_CRITICAL, 1,
+               'Access point %2 changed state to DOWN',
+               'Generated when access point state changes to DOWN.' CONCAT CRLF CONCAT
+               'Parameters:' CONCAT CRLF CONCAT
+               '    1) Access point object ID' CONCAT CRLF CONCAT
+               '    2) Access point name' CONCAT CRLF CONCAT
+               '    3) Access point MAC address' CONCAT CRLF CONCAT
+               '    4) Access point IP address' CONCAT CRLF CONCAT
+               '    5) Access point vendor name' CONCAT CRLF CONCAT
+               '    6) Access point model' CONCAT CRLF CONCAT
+               '    7) Access point serial number'
+       );
 
 /*
 ** SNMP traps
index 1376b70..e6843c6 100644 (file)
@@ -389,11 +389,104 @@ void AccessPoint::updateState(AccessPointState state)
        LockData();
    m_state = state;
    if (m_iStatus != STATUS_UNMANAGED)
-      m_iStatus = (state == AP_ADOPTED) ? STATUS_NORMAL : STATUS_MAJOR;
+      m_iStatus = (state == AP_ADOPTED) ? STATUS_NORMAL : ((state == AP_UNADOPTED) ? STATUS_MAJOR : STATUS_CRITICAL);
    Modify();
        UnlockData();
 
    static const TCHAR *names[] = { _T("id"), _T("name"), _T("macAddr"), _T("ipAddr"), _T("vendor"), _T("model"), _T("serialNumber") };
-   PostEventWithNames((state == AP_ADOPTED) ? EVENT_AP_ADOPTED : EVENT_AP_UNADOPTED, m_nodeId, "ishasss", names,
-      m_dwId, m_szName, m_macAddr, m_dwIpAddr, CHECK_NULL_EX(m_vendor), CHECK_NULL_EX(m_model), CHECK_NULL_EX(m_serialNumber));
+   PostEventWithNames((state == AP_ADOPTED) ? EVENT_AP_ADOPTED : ((state == AP_UNADOPTED) ? EVENT_AP_UNADOPTED : EVENT_AP_DOWN), 
+      m_nodeId, "ishasss", names,
+      m_dwId, m_szName, m_macAddr, m_dwIpAddr, 
+      CHECK_NULL_EX(m_vendor), CHECK_NULL_EX(m_model), CHECK_NULL_EX(m_serialNumber));
+}
+
+/**
+ * Do status poll
+ */
+void AccessPoint::statusPoll(ClientSession *session, UINT32 rqId, Queue *eventQueue, Node *controller)
+{
+   m_pollRequestor = session;
+   AccessPointState state = m_state;
+
+   sendPollerMsg(rqId, _T("   Starting status poll on access point %s\r\n"), m_szName);
+   sendPollerMsg(rqId, _T("      Current access point status is %s\r\n"), g_szStatusText[m_iStatus]);
+
+   /* TODO: read status from controller via driver and use ping as last resort only */
+
+   if (m_dwIpAddr != 0)
+   {
+               UINT32 icmpProxy = 0;
+
+      if (IsZoningEnabled() && (controller->getZoneId() != 0))
+               {
+                       Zone *zone = (Zone *)g_idxZoneByGUID.get(controller->getZoneId());
+                       if (zone != NULL)
+                       {
+                               icmpProxy = zone->getIcmpProxy();
+                       }
+               }
+
+               if (icmpProxy != 0)
+               {
+                       sendPollerMsg(rqId, _T("      Starting ICMP ping via proxy\r\n"));
+                       DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): ping via proxy [%u]"), m_dwId, m_szName, icmpProxy);
+                       Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
+                       if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
+                       {
+                               DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): proxy node found: %s"), m_dwId, m_szName, proxyNode->Name());
+                               AgentConnection *conn = proxyNode->createAgentConnection();
+                               if (conn != NULL)
+                               {
+                                       TCHAR parameter[64], buffer[64];
+
+                                       _sntprintf(parameter, 64, _T("Icmp.Ping(%s)"), IpToStr(m_dwIpAddr, buffer));
+                                       if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
+                                       {
+                                               DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): proxy response: \"%s\""), m_dwId, m_szName, buffer);
+                                               TCHAR *eptr;
+                                               long value = _tcstol(buffer, &eptr, 10);
+                                               if ((*eptr == 0) && (value >= 0))
+                                               {
+                                                       if (value >= 10000)
+                                                       {
+                                       sendPollerMsg(rqId, POLLER_ERROR _T("      no response to ICMP ping\r\n"));
+                        state = AP_DOWN;
+                                                       }
+                                               }
+                                       }
+                                       conn->disconnect();
+                                       delete conn;
+                               }
+                               else
+                               {
+                                       DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): cannot connect to agent on proxy node"), m_dwId, m_szName);
+                                       sendPollerMsg(rqId, POLLER_ERROR _T("      Unable to establish connection with proxy node\r\n"));
+                               }
+                       }
+                       else
+                       {
+                               DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): proxy node not available"), m_dwId, m_szName);
+                               sendPollerMsg(rqId, POLLER_ERROR _T("      ICMP proxy not available\r\n"));
+                       }
+               }
+               else    // not using ICMP proxy
+               {
+                       sendPollerMsg(rqId, _T("      Starting ICMP ping\r\n"));
+                       DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): calling IcmpPing(0x%08X,3,%d,NULL,%d)"), m_dwId, m_szName, htonl(m_dwIpAddr), g_icmpPingTimeout, g_icmpPingSize);
+                       UINT32 dwPingStatus = IcmpPing(htonl(m_dwIpAddr), 3, g_icmpPingTimeout, NULL, g_icmpPingSize);
+                       if (dwPingStatus == ICMP_RAW_SOCK_FAILED)
+                               nxlog_write(MSG_RAW_SOCK_FAILED, EVENTLOG_WARNING_TYPE, NULL);
+                       if (dwPingStatus != ICMP_SUCCESS)
+                       {
+                               sendPollerMsg(rqId, POLLER_ERROR _T("      no response to ICMP ping\r\n"));
+            state = AP_DOWN;
+                       }
+                       DbgPrintf(7, _T("AccessPoint::StatusPoll(%d,%s): ping result %d, state=%d"), m_dwId, m_szName, dwPingStatus, state);
+               }
+   }
+
+   updateState(state);
+
+   sendPollerMsg(rqId, _T("      Access point status after poll is %s\r\n"), g_szStatusText[m_iStatus]);
+       sendPollerMsg(rqId, _T("   Finished status poll on access point %s\r\n"), m_szName);
 }
index 56a8c3c..6628451 100644 (file)
@@ -1267,7 +1267,12 @@ restart_agent_check:
             ((NetworkService *)ppPollList[i])->statusPoll(pSession, dwRqId,
                                                           (Node *)pPollerNode, pQueue);
             break;
+         case OBJECT_ACCESSPOINT:
+                          DbgPrintf(7, _T("StatusPoll(%s): polling access point %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
+            ((AccessPoint *)ppPollList[i])->statusPoll(pSession, dwRqId, pQueue, this);
+            break;
          default:
+            DbgPrintf(7, _T("StatusPoll(%s): skipping object %d [%s] class %d"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name(), ppPollList[i]->Type());
             break;
       }
       ppPollList[i]->decRefCount();
@@ -2376,6 +2381,7 @@ bool Node::confPollSnmp(UINT32 dwRqId)
                                        if (info->getState() == AP_ADOPTED)
                                        adopted++;
 
+               bool newAp = false;
                AccessPoint *ap = (clusterMode == CLUSTER_MODE_STANDALONE) ? findAccessPointByMAC(info->getMacAddr()) : FindAccessPointByMAC(info->getMacAddr());
                                        if (ap == NULL)
                                        {
@@ -2397,12 +2403,14 @@ bool Node::confPollSnmp(UINT32 dwRqId)
                                                ap = new AccessPoint((const TCHAR *)name, info->getMacAddr());
                                                NetObjInsert(ap, TRUE);
                                                DbgPrintf(5, _T("ConfPoll(%s): created new access point object %s [%d]"), m_szName, ap->Name(), ap->Id());
+                  newAp = true;
                                        }
                                        ap->attachToNode(m_dwId);
-                                       if (info->getState() == AP_ADOPTED)
+               ap->setIpAddr(info->getIpAddr());
+                                       if ((info->getState() == AP_ADOPTED) || newAp)
                {
                                           ap->updateRadioInterfaces(info->getRadioInterfaces());
-                                          ap->updateInfo(NULL, info->getModel(), info->getSerial());
+                  ap->updateInfo(info->getVendor(), info->getModel(), info->getSerial());
                }
                                        ap->unhide();
                ap->updateState(info->getState());
index cc85143..cd7e109 100644 (file)
@@ -117,16 +117,19 @@ static UINT32 HandlerAccessPointList(UINT32 version, SNMP_Variable *var, SNMP_Tr
    oid[11] = 1;   // bsnAPDot3MacAddress
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
+   oid[11] = 19;  // bsnApIpAddress
+   request->bindVariable(new SNMP_Variable(oid, nameLen));
+
    oid[11] = 6;   // bsnAPOperationStatus
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
    oid[11] = 3;   // bsnAPName
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
-   oid[11] = 7;   // bsnAPModel
+   oid[11] = 16;  // bsnAPModel
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
-   oid[11] = 17;   // bsnAPSerialNumber
+   oid[11] = 17;  // bsnAPSerialNumber
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
    oid[9] = 2;    // bsnAPIfTable
@@ -145,34 +148,36 @@ static UINT32 HandlerAccessPointList(UINT32 version, SNMP_Variable *var, SNMP_Tr
        delete request;
    if (rcc == SNMP_ERR_SUCCESS)
    {
-      if (response->getNumVariables() == 7)
+      if (response->getNumVariables() == 8)
       {
          BYTE macAddr[16];
          memset(macAddr, 0, sizeof(macAddr));
          var->getRawValue(macAddr, sizeof(macAddr));
 
-         TCHAR name[MAX_OBJECT_NAME], model[MAX_OBJECT_NAME], serial[MAX_OBJECT_NAME];
+         TCHAR ipAddr[32], name[MAX_OBJECT_NAME], model[MAX_OBJECT_NAME], serial[MAX_OBJECT_NAME];
          AccessPointInfo *ap = 
             new AccessPointInfo(
-               macAddr, 
-               (response->getVariable(1)->getValueAsInt() == 1) ? AP_ADOPTED : AP_UNADOPTED,
-               response->getVariable(2)->getValueAsString(name, MAX_OBJECT_NAME), 
-               response->getVariable(3)->getValueAsString(model, MAX_OBJECT_NAME), 
-               response->getVariable(4)->getValueAsString(serial, MAX_OBJECT_NAME));
+               macAddr,
+               ntohl(_t_inet_addr(response->getVariable(1)->getValueAsString(ipAddr, 32))),
+               (response->getVariable(2)->getValueAsInt() == 1) ? AP_ADOPTED : AP_UNADOPTED,
+               response->getVariable(3)->getValueAsString(name, MAX_OBJECT_NAME),
+               _T("Cisco"),   // vendor
+               response->getVariable(4)->getValueAsString(model, MAX_OBJECT_NAME),
+               response->getVariable(5)->getValueAsString(serial, MAX_OBJECT_NAME));
 
          RadioInterfaceInfo radio;
          memset(&radio, 0, sizeof(RadioInterfaceInfo));
          _tcscpy(radio.name, _T("slot0"));
          radio.index = 0;
          response->getVariable(0)->getRawValue(radio.macAddr, MAC_ADDR_LENGTH);
-         radio.channel = response->getVariable(5)->getValueAsInt();
+         radio.channel = response->getVariable(6)->getValueAsInt();
          ap->addRadioInterface(&radio);
 
-         if ((response->getVariable(6)->getType() != ASN_NO_SUCH_INSTANCE) && (response->getVariable(6)->getType() != ASN_NO_SUCH_OBJECT))
+         if ((response->getVariable(7)->getType() != ASN_NO_SUCH_INSTANCE) && (response->getVariable(7)->getType() != ASN_NO_SUCH_OBJECT))
          {
             _tcscpy(radio.name, _T("slot1"));
             radio.index = 1;
-            radio.channel = response->getVariable(6)->getValueAsInt();
+            radio.channel = response->getVariable(7)->getValueAsInt();
             ap->addRadioInterface(&radio);
          }
 
index a641d15..f39dfc9 100644 (file)
@@ -167,7 +167,7 @@ static UINT32 HandlerAccessPointList(UINT32 version, SNMP_Variable *var, SNMP_Tr
             response->getVariable(3)->getRawValue(macAddr, MAC_ADDR_LENGTH);
 
          TCHAR name[MAX_OBJECT_NAME];
-         AccessPointInfo *ap = new AccessPointInfo(macAddr, AP_ADOPTED, var->getValueAsString(name, MAX_OBJECT_NAME), _T(""), _T(""));
+         AccessPointInfo *ap = new AccessPointInfo(macAddr, 0, AP_ADOPTED, var->getValueAsString(name, MAX_OBJECT_NAME), NULL, NULL, NULL);
       
          RadioInterfaceInfo radio;
          memset(&radio, 0, sizeof(RadioInterfaceInfo));
index 1829fc6..0edab6b 100644 (file)
@@ -109,7 +109,7 @@ static UINT32 HandlerAccessPointListUnadopted(UINT32 version, SNMP_Variable *var
    ObjectArray<AccessPointInfo> *apList = (ObjectArray<AccessPointInfo> *)arg;
 
    TCHAR model[128];
-   AccessPointInfo *info = new AccessPointInfo((BYTE *)"\x00\x00\x00\x00\x00\x00", AP_UNADOPTED, NULL, var->getValueAsString(model, 128), NULL);
+   AccessPointInfo *info = new AccessPointInfo((BYTE *)"\x00\x00\x00\x00\x00\x00", 0, AP_UNADOPTED, NULL, NULL, var->getValueAsString(model, 128), NULL);
    apList->add(info);
 
    return SNMP_ERR_SUCCESS;
@@ -145,14 +145,27 @@ static UINT32 HandlerAccessPointListAdopted(UINT32 version, SNMP_Variable *var,
    oid[15] = 8;  // ntwsApStatApStatusApName
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
+   oid[15] = 10; // ntwsApStatApStatusIpAddress
+   request->bindVariable(new SNMP_Variable(oid, nameLen));
+
+   oid[15] = 13; // ntwsApStatApStatusManufacturerId
+   request->bindVariable(new SNMP_Variable(oid, nameLen));
+
    SNMP_PDU *response;
    if (transport->doRequest(request, &response, g_dwSNMPTimeout, 3) == SNMP_ERR_SUCCESS)
    {
-      if (response->getNumVariables() >= 2)
+      if (response->getNumVariables() >= 4)
       {
-         TCHAR model[256], name[256];
-         AccessPointInfo *ap = new AccessPointInfo((BYTE *)var->getValue(), AP_ADOPTED, 
-            response->getVariable(1)->getValueAsString(name, 256), response->getVariable(0)->getValueAsString(model, 256), serial);
+         TCHAR model[256], name[256], vendor[256], ipAddr[32];
+         AccessPointInfo *ap = 
+            new AccessPointInfo(
+               (BYTE *)var->getValue(), 
+               ntohl(_t_inet_addr(response->getVariable(2)->getValueAsString(ipAddr, 32))), 
+               AP_ADOPTED, 
+               response->getVariable(1)->getValueAsString(name, 256),
+               response->getVariable(3)->getValueAsString(vendor, 256),
+               response->getVariable(0)->getValueAsString(model, 256),
+               serial);
          apList->add(ap);
       }
       delete response;
index 121fdf8..d2565c7 100644 (file)
@@ -64,6 +64,7 @@
                        />
                        <Tool
                                Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="$(OutDir)\$(ProjectName).ndd"
                                LinkIncremental="2"
                                GenerateDebugInformation="true"
                        />
                        <Tool
                                Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="$(OutDir)\$(ProjectName).ndd"
                                LinkIncremental="2"
                                GenerateDebugInformation="true"
                        />
                        <Tool
                                Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="$(OutDir)\$(ProjectName).ndd"
                                LinkIncremental="1"
                                GenerateDebugInformation="true"
                        />
                        <Tool
                                Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="$(OutDir)\$(ProjectName).ndd"
                                LinkIncremental="1"
                                GenerateDebugInformation="true"
                                >
                        </File>
                        <File
-                               RelativePath="..\..\include\nxsrvapi.h"
+                               RelativePath=".\ntws.h"
                                >
                        </File>
                        <File
-                               RelativePath=".\ntws.h"
+                               RelativePath="..\..\include\nxsrvapi.h"
                                >
                        </File>
                </Filter>
index c06f2cc..dabc0a5 100644 (file)
@@ -166,7 +166,7 @@ static UINT32 HandlerAccessPointListUnadopted(UINT32 version, SNMP_Variable *var
          break;
    }
 
-   AccessPointInfo *info = new AccessPointInfo((BYTE *)var->getValue(), AP_UNADOPTED, NULL, model, NULL);
+   AccessPointInfo *info = new AccessPointInfo((BYTE *)var->getValue(), 0, AP_UNADOPTED, NULL, NULL, model, NULL);
    apList->add(info);
 
    return SNMP_ERR_SUCCESS;
@@ -261,7 +261,7 @@ static UINT32 HandlerAccessPointListAdopted(UINT32 version, SNMP_Variable *var,
    AccessPointInfo *info;
    if (ret == SNMP_ERR_SUCCESS)
    {
-      info = new AccessPointInfo((BYTE *)var->getValue(), AP_ADOPTED, NULL, model, serial);
+      info = new AccessPointInfo((BYTE *)var->getValue(), 0, AP_ADOPTED, NULL, NULL, model, serial);
       apList->add(info);
    }
 
index d7d6534..5536919 100644 (file)
@@ -96,7 +96,8 @@ enum
 enum AccessPointState
 {
    AP_ADOPTED = 0,
-   AP_UNADOPTED = 1
+   AP_UNADOPTED = 1,
+   AP_DOWN = 2
 };
 
 /**
@@ -131,21 +132,25 @@ class LIBNXSRV_EXPORTABLE AccessPointInfo
 {
 private:
    BYTE m_macAddr[MAC_ADDR_LENGTH];
+   UINT32 m_ipAddr;
    AccessPointState m_state;
    TCHAR *m_name;
+   TCHAR *m_vendor;
    TCHAR *m_model;
    TCHAR *m_serial;
        ObjectArray<RadioInterfaceInfo> *m_radioInterfaces;
 
 public:
-   AccessPointInfo(BYTE *macAddr, AccessPointState state, const TCHAR *name, const TCHAR *model, const TCHAR *serial);
+   AccessPointInfo(BYTE *macAddr, UINT32 ipAddr, AccessPointState state, const TCHAR *name, const TCHAR *vendor, const TCHAR *model, const TCHAR *serial);
    ~AccessPointInfo();
 
        void addRadioInterface(RadioInterfaceInfo *iface);
 
        BYTE *getMacAddr() { return m_macAddr; }
+   UINT32 getIpAddr() { return m_ipAddr; }
        AccessPointState getState() { return m_state; }
        const TCHAR *getName() { return m_name; }
+       const TCHAR *getVendor() { return m_vendor; }
        const TCHAR *getModel() { return m_model; }
        const TCHAR *getSerial() { return m_serial; }
        ObjectArray<RadioInterfaceInfo> *getRadioInterfaces() { return m_radioInterfaces; }
index 84da31f..4e20bec 100644 (file)
@@ -860,6 +860,8 @@ public:
        virtual void CreateMessage(CSCPMessage *pMsg);
    virtual UINT32 ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked = FALSE);
 
+   void statusPoll(ClientSession *session, UINT32 rqId, Queue *eventQueue, Node *controller);
+
        BYTE *getMacAddr() { return m_macAddr; }
        bool isMyRadio(int rfIndex);
        bool isMyRadio(const BYTE *macAddr);
@@ -867,6 +869,8 @@ public:
    AccessPointState getState() { return m_state; }
    Node *getParentNode();
 
+   void setIpAddr(UINT32 ipAddr) { LockData(); m_dwIpAddr = ipAddr; Modify(); UnlockData(); }
+
        void attachToNode(UINT32 nodeId);
        void updateRadioInterfaces(ObjectArray<RadioInterfaceInfo> *ri);
        void updateInfo(const TCHAR *vendor, const TCHAR *model, const TCHAR *serialNumber);
index 10cc673..cd12eb7 100644 (file)
 /**
  * Access point info constructor
  */
-AccessPointInfo::AccessPointInfo(BYTE *macAddr, AccessPointState state, const TCHAR *name, const TCHAR *model, const TCHAR *serial)
+AccessPointInfo::AccessPointInfo(BYTE *macAddr, UINT32 ipAddr, AccessPointState state, const TCHAR *name, const TCHAR *vendor, const TCHAR *model, const TCHAR *serial)
 {
        memcpy(m_macAddr, macAddr, MAC_ADDR_LENGTH);
+   m_ipAddr = ipAddr;
        m_state = state;
        m_name = (name != NULL) ? _tcsdup(name) : NULL;
+       m_vendor = (vendor != NULL) ? _tcsdup(vendor) : NULL;
        m_model = (model != NULL) ? _tcsdup(model) : NULL;
        m_serial = (serial != NULL) ? _tcsdup(serial) : NULL;
        m_radioInterfaces = new ObjectArray<RadioInterfaceInfo>(4, 4, true);
@@ -41,6 +43,7 @@ AccessPointInfo::AccessPointInfo(BYTE *macAddr, AccessPointState state, const TC
 AccessPointInfo::~AccessPointInfo()
 {
    safe_free(m_name);
+   safe_free(m_vendor);
        safe_free(m_model);
        safe_free(m_serial);
        delete m_radioInterfaces;
index af1f4be..41f6cb6 100644 (file)
@@ -360,6 +360,27 @@ static BOOL RecreateTData(const TCHAR *className, bool multipleTables)
 }
 
 /**
+ * Upgrade from V317 to V318
+ */
+static BOOL H_UpgradeFromV317(int currVersion, int newVersion)
+{
+   CHK_EXEC(CreateEventTemplate(EVENT_AP_DOWN, _T("SYS_AP_DOWN"), SEVERITY_CRITICAL, EF_LOG,
+      _T("Access point %2 changed state to DOWN"),
+               _T("Generated when access point state changes to DOWN.\r\n")
+               _T("Parameters:\r\n")
+               _T("    1) Access point object ID\r\n")
+               _T("    2) Access point name\r\n")
+               _T("    3) Access point MAC address\r\n")
+               _T("    4) Access point IP address\r\n")
+               _T("    5) Access point vendor name\r\n")
+               _T("    6) Access point model\r\n")
+               _T("    7) Access point serial number")));
+
+   CHK_EXEC(SQLQuery(_T("UPDATE metadata SET var_value='318' WHERE var_name='SchemaVersion'")));
+   return TRUE;
+}
+
+/**
  * Upgrade from V316 to V317
  */
 static BOOL H_UpgradeFromV316(int currVersion, int newVersion)
@@ -7675,6 +7696,7 @@ static struct
    { 314, 315, H_UpgradeFromV314 },
    { 315, 316, H_UpgradeFromV315 },
    { 316, 317, H_UpgradeFromV316 },
+   { 317, 318, H_UpgradeFromV317 },
    { 0, 0, NULL }
 };