#!/usr/local/bin/perl
# Snmputils module
# managment snmp devices

use Nas;
use Snmputils;
use Socket;

use SNMP_Session;
use SNMP_util;
use BER;

use Carp;
my $threads = 0;
require "Abills/nas.pl";

my $Nas = Nas->new($db, \%conf);
my $Snmputils = Snmputils->new($db, $admin, \%conf);

eval { require threads; };
if (!$@) {
  threads->import();
  $threads = 1;
}
else {

  #print "Can't load 'threads'\n";
  #print $@ if ($conf{debugmods} =~ /LOG_DEBUG/);
  #exit; #return 0;
}

my $debug      = 0;
my %GUEST_VLAN = ();
$FORM{GET_USERS} = 1;

my @association_state = ('initial', 'authenNotAssociated', 'assocAndAuthenticated', 'assocNotAnuthenticated', 'authenticated');

$conf{SNMPUTILS_BINDING_DEPOSIT} = 0 if (!$conf{SNMPUTILS_BINDING_DEPOSIT});

my %loaded_mibs = ();
my %OIDS_HASH   = (
  'iso'               => '1',
  'org'               => '1.3',
  'dod'               => '1.3.6',
  'internet'          => '1.3.6.1',
  'directory'         => '1.3.6.1.1',
  'mgmt'              => '1.3.6.1.2',
  'mib-2'             => '1.3.6.1.2.1',
  'system'            => '1.3.6.1.2.1.1',
  'sysDescr'          => '1.3.6.1.2.1.1.1.0',
  'sysObjectID'       => '1.3.6.1.2.1.1.2.0',
  'sysUpTime'         => '1.3.6.1.2.1.1.3.0',
  'sysUptime'         => '1.3.6.1.2.1.1.3.0',
  'sysContact'        => '1.3.6.1.2.1.1.4.0',
  'sysName'           => '1.3.6.1.2.1.1.5.0',
  'sysLocation'       => '1.3.6.1.2.1.1.6.0',
  'sysServices'       => '1.3.6.1.2.1.1.7.0',
  'interfaces'        => '1.3.6.1.2.1.2',
  'ifNumber'          => '1.3.6.1.2.1.2.1.0',
  'ifTable'           => '1.3.6.1.2.1.2.2',
  'ifEntry'           => '1.3.6.1.2.1.2.2.1',
  'ifIndex'           => '1.3.6.1.2.1.2.2.1.1',
  'ifInOctets'        => '1.3.6.1.2.1.2.2.1.10',
  'ifInUcastPkts'     => '1.3.6.1.2.1.2.2.1.11',
  'ifInNUcastPkts'    => '1.3.6.1.2.1.2.2.1.12',
  'ifInDiscards'      => '1.3.6.1.2.1.2.2.1.13',
  'ifInErrors'        => '1.3.6.1.2.1.2.2.1.14',
  'ifInUnknownProtos' => '1.3.6.1.2.1.2.2.1.15',
  'ifOutOctets'       => '1.3.6.1.2.1.2.2.1.16',
  'ifOutUcastPkts'    => '1.3.6.1.2.1.2.2.1.17',
  'ifOutNUcastPkts'   => '1.3.6.1.2.1.2.2.1.18',
  'ifOutDiscards'     => '1.3.6.1.2.1.2.2.1.19',
  'ifDescr'           => '1.3.6.1.2.1.2.2.1.2',
  'ifOutErrors'       => '1.3.6.1.2.1.2.2.1.20',
  'ifOutQLen'         => '1.3.6.1.2.1.2.2.1.21',
  'ifSpecific'        => '1.3.6.1.2.1.2.2.1.22',
  'ifType'            => '1.3.6.1.2.1.2.2.1.3',
  'ifMtu'             => '1.3.6.1.2.1.2.2.1.4',
  'ifSpeed'           => '1.3.6.1.2.1.2.2.1.5',
  'ifPhysAddress'     => '1.3.6.1.2.1.2.2.1.6',

  #    'ifAdminHack'   => '1.3.6.1.2.1.2.2.1.7',
  'ifAdminStatus'              => '1.3.6.1.2.1.2.2.1.7',
  'ifOperHack'                 => '1.3.6.1.2.1.2.2.1.8',
  'ifOperStatus'               => '1.3.6.1.2.1.2.2.1.8',
  'ifLastChange'               => '1.3.6.1.2.1.2.2.1.9',
  'at'                         => '1.3.6.1.2.1.3',
  'atTable'                    => '1.3.6.1.2.1.3.1',
  'atEntry'                    => '1.3.6.1.2.1.3.1.1',
  'atIfIndex'                  => '1.3.6.1.2.1.3.1.1.1',
  'atPhysAddress'              => '1.3.6.1.2.1.3.1.1.2',
  'atNetAddress'               => '1.3.6.1.2.1.3.1.1.3',
  'ip'                         => '1.3.6.1.2.1.4',
  'ipForwarding'               => '1.3.6.1.2.1.4.1',
  'ipOutRequests'              => '1.3.6.1.2.1.4.10',
  'ipOutDiscards'              => '1.3.6.1.2.1.4.11',
  'ipOutNoRoutes'              => '1.3.6.1.2.1.4.12',
  'ipReasmTimeout'             => '1.3.6.1.2.1.4.13',
  'ipReasmReqds'               => '1.3.6.1.2.1.4.14',
  'ipReasmOKs'                 => '1.3.6.1.2.1.4.15',
  'ipReasmFails'               => '1.3.6.1.2.1.4.16',
  'ipFragOKs'                  => '1.3.6.1.2.1.4.17',
  'ipFragFails'                => '1.3.6.1.2.1.4.18',
  'ipFragCreates'              => '1.3.6.1.2.1.4.19',
  'ipDefaultTTL'               => '1.3.6.1.2.1.4.2',
  'ipAddrTable'                => '1.3.6.1.2.1.4.20',
  'ipAddrEntry'                => '1.3.6.1.2.1.4.20.1',
  'ipAdEntAddr'                => '1.3.6.1.2.1.4.20.1.1',
  'ipAdEntIfIndex'             => '1.3.6.1.2.1.4.20.1.2',
  'ipAdEntNetMask'             => '1.3.6.1.2.1.4.20.1.3',
  'ipAdEntBcastAddr'           => '1.3.6.1.2.1.4.20.1.4',
  'ipAdEntReasmMaxSize'        => '1.3.6.1.2.1.4.20.1.5',
  'ipRouteTable'               => '1.3.6.1.2.1.4.21',
  'ipRouteEntry'               => '1.3.6.1.2.1.4.21.1',
  'ipRouteDest'                => '1.3.6.1.2.1.4.21.1.1',
  'ipRouteAge'                 => '1.3.6.1.2.1.4.21.1.10',
  'ipRouteMask'                => '1.3.6.1.2.1.4.21.1.11',
  'ipRouteMetric5'             => '1.3.6.1.2.1.4.21.1.12',
  'ipRouteInfo'                => '1.3.6.1.2.1.4.21.1.13',
  'ipRouteIfIndex'             => '1.3.6.1.2.1.4.21.1.2',
  'ipRouteMetric1'             => '1.3.6.1.2.1.4.21.1.3',
  'ipRouteMetric2'             => '1.3.6.1.2.1.4.21.1.4',
  'ipRouteMetric3'             => '1.3.6.1.2.1.4.21.1.5',
  'ipRouteMetric4'             => '1.3.6.1.2.1.4.21.1.6',
  'ipRouteNextHop'             => '1.3.6.1.2.1.4.21.1.7',
  'ipRouteType'                => '1.3.6.1.2.1.4.21.1.8',
  'ipRouteProto'               => '1.3.6.1.2.1.4.21.1.9',
  'ipNetToMediaTable'          => '1.3.6.1.2.1.4.22',
  'ipNetToMediaEntry'          => '1.3.6.1.2.1.4.22.1',
  'ipNetToMediaIfIndex'        => '1.3.6.1.2.1.4.22.1.1',
  'ipNetToMediaPhysAddress'    => '1.3.6.1.2.1.4.22.1.2',
  'ipNetToMediaNetAddress'     => '1.3.6.1.2.1.4.22.1.3',
  'ipNetToMediaType'           => '1.3.6.1.2.1.4.22.1.4',
  'ipRoutingDiscards'          => '1.3.6.1.2.1.4.23',
  'ipInReceives'               => '1.3.6.1.2.1.4.3',
  'ipInHdrErrors'              => '1.3.6.1.2.1.4.4',
  'ipInAddrErrors'             => '1.3.6.1.2.1.4.5',
  'ipForwDatagrams'            => '1.3.6.1.2.1.4.6',
  'ipInUnknownProtos'          => '1.3.6.1.2.1.4.7',
  'ipInDiscards'               => '1.3.6.1.2.1.4.8',
  'ipInDelivers'               => '1.3.6.1.2.1.4.9',
  'icmp'                       => '1.3.6.1.2.1.5',
  'icmpInMsgs'                 => '1.3.6.1.2.1.5.1',
  'icmpInTimestamps'           => '1.3.6.1.2.1.5.10',
  'icmpInTimestampReps'        => '1.3.6.1.2.1.5.11',
  'icmpInAddrMasks'            => '1.3.6.1.2.1.5.12',
  'icmpInAddrMaskReps'         => '1.3.6.1.2.1.5.13',
  'icmpOutMsgs'                => '1.3.6.1.2.1.5.14',
  'icmpOutErrors'              => '1.3.6.1.2.1.5.15',
  'icmpOutDestUnreachs'        => '1.3.6.1.2.1.5.16',
  'icmpOutTimeExcds'           => '1.3.6.1.2.1.5.17',
  'icmpOutParmProbs'           => '1.3.6.1.2.1.5.18',
  'icmpOutSrcQuenchs'          => '1.3.6.1.2.1.5.19',
  'icmpInErrors'               => '1.3.6.1.2.1.5.2',
  'icmpOutRedirects'           => '1.3.6.1.2.1.5.20',
  'icmpOutEchos'               => '1.3.6.1.2.1.5.21',
  'icmpOutEchoReps'            => '1.3.6.1.2.1.5.22',
  'icmpOutTimestamps'          => '1.3.6.1.2.1.5.23',
  'icmpOutTimestampReps'       => '1.3.6.1.2.1.5.24',
  'icmpOutAddrMasks'           => '1.3.6.1.2.1.5.25',
  'icmpOutAddrMaskReps'        => '1.3.6.1.2.1.5.26',
  'icmpInDestUnreachs'         => '1.3.6.1.2.1.5.3',
  'icmpInTimeExcds'            => '1.3.6.1.2.1.5.4',
  'icmpInParmProbs'            => '1.3.6.1.2.1.5.5',
  'icmpInSrcQuenchs'           => '1.3.6.1.2.1.5.6',
  'icmpInRedirects'            => '1.3.6.1.2.1.5.7',
  'icmpInEchos'                => '1.3.6.1.2.1.5.8',
  'icmpInEchoReps'             => '1.3.6.1.2.1.5.9',
  'tcp'                        => '1.3.6.1.2.1.6',
  'tcpRtoAlgorithm'            => '1.3.6.1.2.1.6.1',
  'tcpInSegs'                  => '1.3.6.1.2.1.6.10',
  'tcpOutSegs'                 => '1.3.6.1.2.1.6.11',
  'tcpRetransSegs'             => '1.3.6.1.2.1.6.12',
  'tcpConnTable'               => '1.3.6.1.2.1.6.13',
  'tcpConnEntry'               => '1.3.6.1.2.1.6.13.1',
  'tcpConnState'               => '1.3.6.1.2.1.6.13.1.1',
  'tcpConnLocalAddress'        => '1.3.6.1.2.1.6.13.1.2',
  'tcpConnLocalPort'           => '1.3.6.1.2.1.6.13.1.3',
  'tcpConnRemAddress'          => '1.3.6.1.2.1.6.13.1.4',
  'tcpConnRemPort'             => '1.3.6.1.2.1.6.13.1.5',
  'tcpInErrs'                  => '1.3.6.1.2.1.6.14',
  'tcpOutRsts'                 => '1.3.6.1.2.1.6.15',
  'tcpRtoMin'                  => '1.3.6.1.2.1.6.2',
  'tcpRtoMax'                  => '1.3.6.1.2.1.6.3',
  'tcpMaxConn'                 => '1.3.6.1.2.1.6.4',
  'tcpActiveOpens'             => '1.3.6.1.2.1.6.5',
  'tcpPassiveOpens'            => '1.3.6.1.2.1.6.6',
  'tcpAttemptFails'            => '1.3.6.1.2.1.6.7',
  'tcpEstabResets'             => '1.3.6.1.2.1.6.8',
  'tcpCurrEstab'               => '1.3.6.1.2.1.6.9',
  'udp'                        => '1.3.6.1.2.1.7',
  'udpInDatagrams'             => '1.3.6.1.2.1.7.1',
  'udpNoPorts'                 => '1.3.6.1.2.1.7.2',
  'udpInErrors'                => '1.3.6.1.2.1.7.3',
  'udpOutDatagrams'            => '1.3.6.1.2.1.7.4',
  'udpTable'                   => '1.3.6.1.2.1.7.5',
  'udpEntry'                   => '1.3.6.1.2.1.7.5.1',
  'udpLocalAddress'            => '1.3.6.1.2.1.7.5.1.1',
  'udpLocalPort'               => '1.3.6.1.2.1.7.5.1.2',
  'egp'                        => '1.3.6.1.2.1.8',
  'egpInMsgs'                  => '1.3.6.1.2.1.8.1',
  'egpInErrors'                => '1.3.6.1.2.1.8.2',
  'egpOutMsgs'                 => '1.3.6.1.2.1.8.3',
  'egpOutErrors'               => '1.3.6.1.2.1.8.4',
  'egpNeighTable'              => '1.3.6.1.2.1.8.5',
  'egpNeighEntry'              => '1.3.6.1.2.1.8.5.1',
  'egpNeighState'              => '1.3.6.1.2.1.8.5.1.1',
  'egpNeighStateUps'           => '1.3.6.1.2.1.8.5.1.10',
  'egpNeighStateDowns'         => '1.3.6.1.2.1.8.5.1.11',
  'egpNeighIntervalHello'      => '1.3.6.1.2.1.8.5.1.12',
  'egpNeighIntervalPoll'       => '1.3.6.1.2.1.8.5.1.13',
  'egpNeighMode'               => '1.3.6.1.2.1.8.5.1.14',
  'egpNeighEventTrigger'       => '1.3.6.1.2.1.8.5.1.15',
  'egpNeighAddr'               => '1.3.6.1.2.1.8.5.1.2',
  'egpNeighAs'                 => '1.3.6.1.2.1.8.5.1.3',
  'egpNeighInMsgs'             => '1.3.6.1.2.1.8.5.1.4',
  'egpNeighInErrs'             => '1.3.6.1.2.1.8.5.1.5',
  'egpNeighOutMsgs'            => '1.3.6.1.2.1.8.5.1.6',
  'egpNeighOutErrs'            => '1.3.6.1.2.1.8.5.1.7',
  'egpNeighInErrMsgs'          => '1.3.6.1.2.1.8.5.1.8',
  'egpNeighOutErrMsgs'         => '1.3.6.1.2.1.8.5.1.9',
  'egpAs'                      => '1.3.6.1.2.1.8.6',
  'transmission'               => '1.3.6.1.2.1.10',
  'frame-relay'                => '1.3.6.1.2.1.10.32',
  'frDlcmiTable'               => '1.3.6.1.2.1.10.32.1',
  'frDlcmiEntry'               => '1.3.6.1.2.1.10.32.1.1',
  'frDlcmiIfIndex'             => '1.3.6.1.2.1.10.32.1.1.1',
  'frDlcmiState'               => '1.3.6.1.2.1.10.32.1.1.2',
  'frDlcmiAddress'             => '1.3.6.1.2.1.10.32.1.1.3',
  'frDlcmiAddressLen'          => '1.3.6.1.2.1.10.32.1.1.4',
  'frDlcmiPollingInterval'     => '1.3.6.1.2.1.10.32.1.1.5',
  'frDlcmiFullEnquiryInterval' => '1.3.6.1.2.1.10.32.1.1.6',
  'frDlcmiErrorThreshold'      => '1.3.6.1.2.1.10.32.1.1.7',
  'frDlcmiMonitoredEvents'     => '1.3.6.1.2.1.10.32.1.1.8',
  'frDlcmiMaxSupportedVCs'     => '1.3.6.1.2.1.10.32.1.1.9',
  'frDlcmiMulticast'           => '1.3.6.1.2.1.10.32.1.1.10',
  'frCircuitTable'             => '1.3.6.1.2.1.10.32.2',
  'frCircuitEntry'             => '1.3.6.1.2.1.10.32.2.1',
  'frCircuitIfIndex'           => '1.3.6.1.2.1.10.32.2.1.1',
  'frCircuitDlci'              => '1.3.6.1.2.1.10.32.2.1.2',
  'frCircuitState'             => '1.3.6.1.2.1.10.32.2.1.3',
  'frCircuitReceivedFECNs'     => '1.3.6.1.2.1.10.32.2.1.4',
  'frCircuitReceivedBECNs'     => '1.3.6.1.2.1.10.32.2.1.5',
  'frCircuitSentFrames'        => '1.3.6.1.2.1.10.32.2.1.6',
  'frCircuitSentOctets'        => '1.3.6.1.2.1.10.32.2.1.7',
  'frOutOctets'                => '1.3.6.1.2.1.10.32.2.1.7',
  'frCircuitReceivedFrames'    => '1.3.6.1.2.1.10.32.2.1.8',
  'frCircuitReceivedOctets'    => '1.3.6.1.2.1.10.32.2.1.9',
  'frInOctets'                 => '1.3.6.1.2.1.10.32.2.1.9',
  'frCircuitCreationTime'      => '1.3.6.1.2.1.10.32.2.1.10',
  'frCircuitLastTimeChange'    => '1.3.6.1.2.1.10.32.2.1.11',
  'frCircuitCommittedBurst'    => '1.3.6.1.2.1.10.32.2.1.12',
  'frCircuitExcessBurst'       => '1.3.6.1.2.1.10.32.2.1.13',
  'frCircuitThroughput'        => '1.3.6.1.2.1.10.32.2.1.14',
  'frErrTable'                 => '1.3.6.1.2.1.10.32.3',
  'frErrEntry'                 => '1.3.6.1.2.1.10.32.3.1',
  'frErrIfIndex'               => '1.3.6.1.2.1.10.32.3.1.1',
  'frErrType'                  => '1.3.6.1.2.1.10.32.3.1.2',
  'frErrData'                  => '1.3.6.1.2.1.10.32.3.1.3',
  'frErrTime'                  => '1.3.6.1.2.1.10.32.3.1.4',
  'frame-relay-globals'        => '1.3.6.1.2.1.10.32.4',
  'frTrapState'                => '1.3.6.1.2.1.10.32.4.1',
  'snmp'                       => '1.3.6.1.2.1.11',
  'snmpInPkts'                 => '1.3.6.1.2.1.11.1',
  'snmpInBadValues'            => '1.3.6.1.2.1.11.10',
  'snmpInReadOnlys'            => '1.3.6.1.2.1.11.11',
  'snmpInGenErrs'              => '1.3.6.1.2.1.11.12',
  'snmpInTotalReqVars'         => '1.3.6.1.2.1.11.13',
  'snmpInTotalSetVars'         => '1.3.6.1.2.1.11.14',
  'snmpInGetRequests'          => '1.3.6.1.2.1.11.15',
  'snmpInGetNexts'             => '1.3.6.1.2.1.11.16',
  'snmpInSetRequests'          => '1.3.6.1.2.1.11.17',
  'snmpInGetResponses'         => '1.3.6.1.2.1.11.18',
  'snmpInTraps'                => '1.3.6.1.2.1.11.19',
  'snmpOutPkts'                => '1.3.6.1.2.1.11.2',
  'snmpOutTooBigs'             => '1.3.6.1.2.1.11.20',
  'snmpOutNoSuchNames'         => '1.3.6.1.2.1.11.21',
  'snmpOutBadValues'           => '1.3.6.1.2.1.11.22',
  'snmpOutGenErrs'             => '1.3.6.1.2.1.11.24',
  'snmpOutGetRequests'         => '1.3.6.1.2.1.11.25',
  'snmpOutGetNexts'            => '1.3.6.1.2.1.11.26',
  'snmpOutSetRequests'         => '1.3.6.1.2.1.11.27',
  'snmpOutGetResponses'        => '1.3.6.1.2.1.11.28',
  'snmpOutTraps'               => '1.3.6.1.2.1.11.29',
  'snmpInBadVersions'          => '1.3.6.1.2.1.11.3',
  'snmpEnableAuthenTraps'      => '1.3.6.1.2.1.11.30',
  'snmpInBadCommunityNames'    => '1.3.6.1.2.1.11.4',
  'snmpInBadCommunityUses'     => '1.3.6.1.2.1.11.5',
  'snmpInASNParseErrs'         => '1.3.6.1.2.1.11.6',
  'snmpInTooBigs'              => '1.3.6.1.2.1.11.8',
  'snmpInNoSuchNames'          => '1.3.6.1.2.1.11.9',
  'ifName'                     => '1.3.6.1.2.1.31.1.1.1.1',
  'ifInMulticastPkts'          => '1.3.6.1.2.1.31.1.1.1.2',
  'ifInBroadcastPkts'          => '1.3.6.1.2.1.31.1.1.1.3',
  'ifOutMulticastPkts'         => '1.3.6.1.2.1.31.1.1.1.4',
  'ifOutBroadcastPkts'         => '1.3.6.1.2.1.31.1.1.1.5',
  'ifHCInOctets'               => '1.3.6.1.2.1.31.1.1.1.6',
  'ifHCInUcastPkts'            => '1.3.6.1.2.1.31.1.1.1.7',
  'ifHCInMulticastPkts'        => '1.3.6.1.2.1.31.1.1.1.8',
  'ifHCInBroadcastPkts'        => '1.3.6.1.2.1.31.1.1.1.9',
  'ifHCOutOctets'              => '1.3.6.1.2.1.31.1.1.1.10',
  'ifHCOutUcastPkts'           => '1.3.6.1.2.1.31.1.1.1.11',
  'ifHCOutMulticastPkts'       => '1.3.6.1.2.1.31.1.1.1.12',
  'ifHCOutBroadcastPkts'       => '1.3.6.1.2.1.31.1.1.1.13',
  'ifLinkUpDownTrapEnable'     => '1.3.6.1.2.1.31.1.1.1.14',
  'ifHighSpeed'                => '1.3.6.1.2.1.31.1.1.1.15',
  'ifPromiscuousMode'          => '1.3.6.1.2.1.31.1.1.1.16',
  'ifConnectorPresent'         => '1.3.6.1.2.1.31.1.1.1.17',
  'ifAlias'                    => '1.3.6.1.2.1.31.1.1.1.18',
  'ifCounterDiscontinuityTime' => '1.3.6.1.2.1.31.1.1.1.19',
  'experimental'               => '1.3.6.1.3',
  'private'                    => '1.3.6.1.4',
  'enterprises'                => '1.3.6.1.4.1',
);

#*******************************************************************
#
#
#*******************************************************************
sub snmputils_monitor {

  my %info      = ();
  my %func_hash = (
    'pm25'          => \&snmputils_portmaster,
    'patton'        => \&snmputils_patton_dialin,
    'cisco_air'     => \&snmputils_ciscoair,
    'docsis_modems' => \&snmputils_docsis_modems,
    'bsr1000'       => \&snmputils_docsis_modems,
    'dlink_pb'      => \&snmputils_dlink_pb_monitor,
    'mikrotik_info' => \&snmputils_mikrotik_info,
    'zyxel_smf'     => \&snmputils_zyxel_smf_monitor
  );

  $info{NAS_TYPES} = $html->form_select(
    'NAS_TYPE',
    {
      SELECTED => $FORM{NAS_TYPE},
      SEL_HASH => {
        'pm25'          => 'Portmaster 2/3',
        'patton'        => 'Patton RAS 29xx',
        'cisco_air'     => 'Cisco Aironets',
        'mikrotik'      => 'Mikrotik (not work yet)',
        'bsr1000'       => 'BSR1000 Modems',
        'docsis'        => 'Docsis modems',
        'dlink_pb'      => 'D-Link port binding',
        'zyxel_smf'     => 'Zyxel Static MAC Forwarding',
        'mikrotik_info' => "Mikrotik $_INFO"
      },
      NO_ID => 1
    }
  );

  my $table = $html->table(
    {
      width       => '100%',
      title_plain => [
        "$_TYPE: " . $info{NAS_TYPES},
        "HOST: " . $html->form_input('SNMP_HOST', "$FORM{SNMP_HOST}"),
        "COMMUNITY: " . $html->form_input('SNMP_COMMUNITY', "$FORM{SNMP_COMMUNITY}"),
        "$_REFRESH (sec): " . $html->form_input('REFRESH', int($FORM{REFRESH}), { SIZE => 4 }),
        $html->form_input('SHOW', $_SHOW, { TYPE => 'SUBMIT' })
      ],
    }
  );

  print $html->form_main(
    {
      CONTENT => $table->show(),
      HIDDEN  => { index => "$index" },
      METHOD  => 'GET'
    }
  );

  if ($FORM{change}) {
    snmp_info_form();
  }

  if ($FORM{HOST}) {

    #    $func_hash{$NAS_TYPE}->();
  }
  elsif ($FORM{NAS_TYPE}) {
    $func_hash{ $FORM{NAS_TYPE} }->();
  }
}

#**********************************************************
#
#**********************************************************
sub hex2bin {
  my ($digit) = shift;

  print $no_revb
  ? unpack("B4", pack("H", $digit))
  : substr(unpack("b8", pack("H", $digit)), -4);
  print "$char";
}

#**********************************************************
# HOST,
# COMMUNITY:
# IP/MAC
#
#
#**********************************************************
sub snmputils_periodic {
  my ($attr) = @_;

  my $debug = $attr->{DEBUG} || 0;
  my $debug_output = '';

  if ($conf{SNMPUTILS_CHANGE_VLAN}) {
    use Dhcphosts;
    my $Dhcphosts = Dhcphosts->new($db, $admin, \%conf);
    my $list = $Dhcphosts->networks_list({ PAGE_ROWS => 10000, SORT => 2 });
    foreach my $line (@$list) {
      $GUEST_VLAN{ $line->[0] } = $line->[8];
    }
  }

  #Get nas servers TYPE: dlink_pb
  my $list = $Nas->list(
    {
      PAGE_ROWS => 100000,
      DISABLE   => 0,
      NAS_IDS   => ($attr->{NAS_IDS}) ? $attr->{NAS_IDS} : undef
    }
  );

  foreach my $line (@$list) {
    my $type = $line->[4];
    $debug_output .= "NAS ID: $line->[0] TYPE: $type MNG INFO: $line->[9]\@$line->[11] $line->[12]\n" if ($debug > 1);
    my %CONF_HASH = (
      NAS_ID       => $line->[0],
      MNG_PASSWORD => $line->[11],
      MNG_HOST     => $line->[9],
      RAD_PAIRS    => $line->[12],
      NAS_TYPE     => $line->[4],
      DEBUG        => $debug
    );

    #GET users for this NAS
    if ($conf{SNMPUTILS_CHANGE_VLAN}) {
      $debug_output .= "Guest VLAN\n" if ($debug > 0);
      $debug_output .= snmputils_chg_vlan({%CONF_HASH});
    }
    elsif ($type eq 'dlink_pb') {
      $debug_output .= "D-Link Port binding\n" if ($debug > 0);
      $debug_output .= snmputils_dlink_pb({%CONF_HASH});
    }
    elsif ($type eq 'qbridge') {
      $debug_output .= "Static MAC Forwarding\n" if ($debug > 0);
      $debug_output .= snmputils_qbridge({%CONF_HASH});
    }
    elsif ($type eq 'celan') {
      $debug_output .= "CeLAN MACs Binding\n" if ($debug > 0);
      $debug_output .= snmputils_celan_macs({%CONF_HASH});
    }
  }

  $DEBUG = $debug_output;
  return $debug_output;
}

#**********************************************************
# Change work and guest vlans
#
# edge-core 3526
#**********************************************************
sub snmputils_chg_vlan {
  my ($attr) = @_;

  my $debug          = $attr->{DEBUG} || 0;
  my $NAS_ID         = $attr->{NAS_ID};          # line->[0];
  my $MNG_PASSWORD   = $attr->{MNG_PASSWORD};    # line->[11];
  my $MNG_HOST       = $attr->{MNG_HOST};        # $line->[9];
  my $RAD_PAIRS      = $attr->{RAD_PAIRS};       #$line->[12];
  my $version        = '';
  my $debug_output   = '';
  my $SNMP_COMMUNITY = '';

  if (!$MNG_PASSWORD && !$MNG_HOST) {
    print "Not defined Snmp Community\n";
    return 0;
  }

  my $list = $Snmputils->snmputils_nas_ipmac(
    {
      NAS_ID    => $NAS_ID,
      PG        => 0,
      PAGE_ROWS => 1000000
    }
  );

  #get users for snmp_binding
  my @switch_ports = split(//, '000000000000000000000000000000000000000000000000');
  my %VLANS        = ();
  my %REMOVE_VLANS = ();
  foreach my $line (@$list) {
    my $user_ports = $ports || '';
    my $vlan       = $line->[6];
    my $network_id = $line->[10];
    if ($line->[7]) {
      $user_ports = $line->[7];
    }

    $debug_output .= "USER ALLOW NAS: " . (($line->[0]) ? $line->[0] : '') . " UID: $line->[1] IP: $line->[2] MAC: $line->[3] VID: $vlan PORT: $user_ports NETWORK: $line->[10]\n" if ($debug > 2);
    if ($line->[4] >= $conf{SNMPUTILS_BINDING_DEPOSIT} && $line->[11] == 0) {
      if ($vlan) {
        push @{ $VLANS{$vlan} }, $user_ports;
        if ($GUEST_VLAN{$network_id}) {
          push @{ $REMOVE_VLANS{ $GUEST_VLAN{$network_id} } }, $user_ports;
        }
      }
    }
    else {
      if ($GUEST_VLAN{$network_id}) {
        push @{ $VLANS{ $GUEST_VLAN{$network_id} } }, $user_ports;
        push @{ $REMOVE_VLANS{$vlan} }, $user_ports;
      }
      $debug_output .= " Negative deposit\n" if ($debug > 2);
    }
  }

  $version = snmpget($SNMP_COMMUNITY, ".1.3.6.1.2.1.1.1.0");
  $version = '' if (!$version);
  print "$version \n" if ($debug > 3);

#       3526,  3526 - 25-26  ;  3528  3028,  3528 - 25-28  ;  3052 - 49-50,  3550 - 49-50  
  my %RESERVED_PORTS = (
    25 => 1,
    26 => 1
  );

  #3028 (25-28), #3528 (25-28)
  if ($version =~ /3028/ || $version =~ /3528/) {
    %RESERVED_PORTS = (
      25 => 1,
      26 => 1,
      27 => 1,
      28 => 1
    );
  }
  elsif ($version =~ /3200\-28/) {
    %RESERVED_PORTS = (
      25 => 1,
      26 => 1,
      27 => 1,
      28 => 1
    );
  }
  elsif ($version =~ /3200\-18/) {
    %RESERVED_PORTS = (
      17 => 1,
      18 => 1
    );
  }

  # 3052 (49-52)
  elsif ($version =~ /3052/) {
    %RESERVED_PORTS = (
      49 => 1,
      50 => 1,
      51 => 1,
      52 => 1
    );
  }

  #3550 (49-50)
  elsif ($version =~ /3550/) {
    %RESERVED_PORTS = (
      49 => 1,
      50 => 1,
    );
  }

  if ($attr->{NAS_TYPE} eq 'edge_core' || $attr->{NAS_TYPE} eq 'dlink_pb') {
    my $ports_map = 'B*';

    if ($version =~ /ES3528M/ || $version =~ /ES3526/) {
      goto ADD;
    }

    DEL:

    #Remove ports from Vlans
    while (my ($vlan, $ports_arr) = each %REMOVE_VLANS) {
      $debug_output .= "REMOVE VLAN: $vlan PORTS: " . join(',', @$ports_arr) . "\n";

      my $oid = '1.3.6.1.2.1.17.7.1.4.3.1.2.';
      my $cure_ports = snmpget($SNMP_COMMUNITY, "$oid$vlan");

      if (!$cure_ports) {
        $debug_output .= "Not exist\n" if ($debug > 2);
        next;
      }

      @switch_ports = split(//, unpack("$ports_map", $cure_ports));
      my @dlink_ports = @switch_ports;

      if ($attr->{NAS_TYPE} eq 'edge_core') {
        foreach my $port (@$ports_arr) {
          if ($RESERVED_PORTS{$port}) {
            next;
          }
          $switch_ports[ int($port - 1) ] = 0;
        }
      }
      else {
        foreach my $port (@$ports_arr) {
          if ($RESERVED_PORTS{$port}) {
            $dlink_ports[ int($port - 1) ] = 0 if ($attr->{NAS_TYPE} eq 'dlink_pb');
            next;
          }
          $dlink_ports[ int($port - 1) ]  = 0;
          $switch_ports[ int($port - 1) ] = 0;
        }
      }
      my $ports_bin = pack("$ports_map", join("", @switch_ports));

      #Dlink pre functions
      if ($attr->{NAS_TYPE} eq 'dlink_pb') {
        foreach my $port (keys %RESERVED_PORTS) {
          $dlink_ports[ $port - 1 ] = 0;
        }

        if (snmpset($SNMP_COMMUNITY, "1.3.6.1.2.1.17.7.1.4.3.1.4.$vlan", 'string', pack("$ports_map", join("", @dlink_ports)))) {
          $debug_output .= "Dlink 1.3.6.1.2.1.17.7.1.4.3.1.4.$vlan PORTS: " . join('', @dlink_ports) . "/" . unpack("H*", pack("$ports_map", join("", @dlink_ports))) . "\n" if ($debug > 3);
        }
        else {
          print "Error: $SNMP_COMMUNITY $oid$vlan / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg\n ";
        }
      }

      if ($debug > 3) {
        $debug_output .= "SNMP: $oid$vlan PORTS: " . unpack("$ports_map", $ports_bin) . "/" . unpack("H*", $ports_bin) . "\n";
      }

      if (snmpset($SNMP_COMMUNITY, "$oid$vlan", 'string', $ports_bin)) {

      }
      else {
        print "Error: $SNMP_COMMUNITY $oid$vlan / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
      }

      #$RESULT->{UNTAGED_PORTS}{$GUEST_VLAN} =snmpget($SNMP_COMMUNITY, "1.3.6.1.2.1.17.7.1.4.3.1.4.$GUEST_VLAN", $ports);
    }

    if ($version =~ /ES3528M/ || $version =~ /ES3526/) {
      $DEBUG = $debug_output;
      goto SAVE_CONF;
      return $debug_output;
    }

    ADD:

    #Add ports to Vlans
    while (my ($vlan, $ports_arr) = each %VLANS) {
      $debug_output .= "ADD VLAN: $vlan PORTS: " . join(',', @$ports_arr) . "\n";

      my $oid = '1.3.6.1.2.1.17.7.1.4.3.1.4.';
      my $cure_ports = snmpget($SNMP_COMMUNITY, "$oid$vlan");

      if (!$cure_ports) {
        $debug_output .= "Not exist\n" if ($debug > 2);
        next;
      }

      @switch_ports = split(//, unpack("$ports_map", $cure_ports));

      foreach my $port (@$ports_arr) {
        $switch_ports[ int($port - 1) ] = 1;
      }

      my $ports_bin = pack("$ports_map", join("", @switch_ports));

      #Dlink pre functions
      if ($attr->{NAS_TYPE} eq 'dlink_pb') {

        #Get dlink ports
        my $cure_ports = snmpget($SNMP_COMMUNITY, '1.3.6.1.2.1.17.7.1.4.3.1.2.' . $vlan);
        my @dlink_all_ports = split(//, unpack("$ports_map", $cure_ports));
        my @reset_ports = ();

        for (my $i = 0 ; $i <= $#switch_ports ; $i++) {
          if ($RESERVED_PORTS{ ($i + 1) }) {
            $reset_ports[$i] = 0;
          }
          else {
            $dlink_all_ports[$i] = $switch_ports[$i];
            $reset_ports[$i]     = 0;
          }
        }

        if (snmpset($SNMP_COMMUNITY, "$oid$vlan", 'string', pack("$ports_map", join("", @reset_ports)))) {
        }
        else {
          print "Error: $SNMP_COMMUNITY $oid$vlan / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg\n ";
        }

        if (snmpset($SNMP_COMMUNITY, "1.3.6.1.2.1.17.7.1.4.3.1.2.$vlan", 'string', pack("$ports_map", join("", @dlink_all_ports)))) {
          $debug_output .= "SNMP DLINK: 1.3.6.1.2.1.17.7.1.4.3.1.2.$vlan PORTS: " . unpack("$ports_map", pack("$ports_map", join("", @dlink_all_ports))) . "/" . unpack("H*", pack("$ports_map", join("", @dlink_all_ports))) . "\n";
        }
        else {
          print "Error: $SNMP_COMMUNITY $oid$vlan / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg\n ";
        }
      }

      if ($debug > 3) {
        $debug_output .= "SNMP: $oid$vlan PORTS: " . unpack("$ports_map", $ports_bin) . "/" . unpack("H*", $ports_bin) . "\n";
      }

      #Untaged
      if (snmpset($SNMP_COMMUNITY, "$oid$vlan", 'string', $ports_bin)) {

        #add port for edge core
        if ($attr->{NAS_TYPE} eq 'edge_core') {
          foreach my $port (@$ports_arr) {
            if ($debug > 3) {
              $debug_output .= "SNMP: 1.3.6.1.2.1.17.7.1.4.5.1.1.$port gauge32 $vlan\n";
            }

            if (snmpset($SNMP_COMMUNITY, "1.3.6.1.2.1.17.7.1.4.5.1.1.$port", 'gauge32', $vlan)) {
            }
            else {
              print "Error: $SNMP_COMMUNITY $oid$vlan / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg\n";
            }
          }
        }
      }
      else {
        print "Error: $SNMP_COMMUNITY $oid$vlan / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg\n";
      }

    }

    if ($version =~ /ES3528M/ || $version =~ /ES3526/) {
      goto DEL;
    }

  }
  elsif ($attr->{NAS_TYPE} eq 'dlink_pb') {

  }

  SAVE_CONF:

  #save config
  if ($conf{SNMPUTILS_SAVE_CONF}) {
    if ($attr->{NAS_TYPE} eq 'edge_core') {
      $debug_output .= snmputils_edgecore_save_conf({ SNMP_COMMUNITY => $SNMP_COMMUNITY, VERSION => $version });
    }
    else {
      $debug_output .= snmputils_dlink_save_conf({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
    }
  }

  $DEBUG = $debug_output;
  return $debug_output;
}

#**********************************************************
# HOST,
# COMMUNITY:
# IP/MAC
#
#
#**********************************************************
sub snmputils_qbridge {
  my ($attr) = @_;

  my $debug          = $attr->{DEBUG} || 0;
  my $NAS_ID         = $attr->{NAS_ID};              # line->[0];
  my $MNG_PASSWORD   = $attr->{MNG_PASSWORD};        # line->[11];
  my $MNG_HOST       = $attr->{MNG_HOST};            # $line->[9];
  my $RAD_PAIRS      = $attr->{RAD_PAIRS};           #$line->[12];
  my $SNMP_COMMUNITY = "$MNG_PASSWORD\@$MNG_HOST";

  my $debug_output = '';
  my ($ACTIVE_MAC, $BLOCK_MAC) = snmputils_smf_list(
    {
      SNMP_COMMUNITY => $SNMP_COMMUNITY,
      SWITCH_INFO    => $SWITCH_INFO,
    }
  );

  my %SERVER_MAC    = ();                            #Now active in server
  my %MUST_ACTIVATE = ();                            #Need to be active
  if ($ACTIVE_MAC->{MAC}) {

    # IP -> MAC
    %SERVER_MAC = %{ $ACTIVE_MAC->{MAC} };
  }

  my $list = $Snmputils->snmputils_nas_ipmac(
    {
      NAS_ID    => $NAS_ID,
      PG        => 0,
      PAGE_ROWS => 100000,
      DISABLE   => 0
    }
  );

  foreach my $line (@$list) {
    my $user_ports = '';
    if ($line->[7]) {
      $user_ports = $line->[7];
    }

    $debug_output .= "$line->[0], UID: $line->[1] IP: $line->[2] MAC: $line->[3] VID: $line->[6] PORT: $line->[7] NAS: $line->[8]\n" if ($debug > 2);
    if ($line->[4] >= $conf{SNMPUTILS_BINDING_DEPOSIT} && ($line->[8] == 0 || $line->[8] == $NAS_ID)) {
      $MUST_ACTIVATE{"$line->[6]-$line->[3]"} = "$line->[7]";
    }
    else {
      $debug_output .= " Negative deposit\n" if ($debug > 2);
    }
  }

  while (my ($vid_mac, $mac) = each %SERVER_MAC) {
    my ($vid, $m) = split(/-/, $vid_mac, 2);
    my $VM = $vid . '-' . $mac;
    $debug_output .= "Server VID: '$VM' MAC: $mac" if ($debug > 0);

    if ($MUST_ACTIVATE{$VM}) {
      delete $MUST_ACTIVATE{$VM};
      delete $SERVER_MAC{$VM};
      $debug_output .= " Skip...\n" if ($debug > 0);
    }
    else {
      if ($debug < 3) {

        my $message = snmputils_zyxel_smf_state(
          {
            SNMP_COMMUNITY => $SNMP_COMMUNITY,
            STATE          => 2,
            PORT_ID        => 0,
            SWITCH_INFO    => $SWITCH_INFO,
            VLAN           => $vid,
            MAC            => $mac,
            DEBUG          => $debug
          }
        );
      }
      $debug_output .= " Delete\n" if ($debug > 0);
    }
  }

  #Must active
  $debug_output .= "Add to server:\n" if ($debug > 0);
  while (my ($vid_mac, $port) = each %MUST_ACTIVATE) {
    $debug_output .= "$vid_mac Port: $port\n" if ($debug > 0);
    my ($vid, $mac) = split(/-/, $vid_mac, 2);

    #Don't add mac to 0 vid
    if ($vid == 0 || $port == 0) {
      $debug_output .= "Error: VID: $vid Port: $port Skip\n" if ($debug > 0);

      #print  ;
      next;
    }

    if ($debug < 3) {
      my $message = snmputils_zyxel_smf_add(
        {
          SNMP_COMMUNITY => $SNMP_COMMUNITY,
          PORT_ID        => $port,
          MAC            => "$mac",
          SWITCH_INFO    => $SWITCH_INFO,
          VLAN           => $vid,
          STATE          => 3,
          DEBUG          => $debug
        }
      );

      $debug_output .= "! $message\n";
    }
  }

  $DEBUG = $debug_output;
  return $debug_output;
}

#**********************************************************
# edgecore save config
#**********************************************************
sub snmputils_edgecore_save_conf {
  my ($attr) = @_;
  my $message = '';

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';

  $SNMP_COMMUNITY .= ':167:2:1';

  my @snmp_cmd = ();
  if ($attr->{VERSION} =~ /3528/) {
    @snmp_cmd = ('1.3.6.1.4.1.259.6.10.94.1.24.1.5.0 integer 2', '1.3.6.1.4.1.259.6.10.94.1.24.1.1.0 integer 2', '1.3.6.1.4.1.259.6.10.94.1.24.1.3.0 integer 3', '1.3.6.1.4.1.259.6.10.94.1.24.1.8.0 integer 2');
  }

  # 3526
  else {
    @snmp_cmd = ('1.3.6.1.4.1.259.8.1.5.1.24.1.1.0 integer 2', '1.3.6.1.4.1.259.8.1.5.1.24.1.3.0 integer 3', '1.3.6.1.4.1.259.8.1.5.1.24.1.8.0 integer 2');
  }

  foreach my $cmd (@snmp_cmd) {
    my ($oid, $type, $value) = split(/ /, $cmd);

    if (snmpset($SNMP_COMMUNITY, $oid, "$type", "$value")) {
      $message .= " Ok\n";
    }
    else {
      $message .= "Error: '$oid' Can't save config\n";
    }
  }

  return $message;
}

#**********************************************************
# HOST,
# COMMUNITY:
# IP/MAC
#
#
#**********************************************************
sub snmputils_dlink_pb {
  my ($attr) = @_;

  my $debug          = $attr->{DEBUG} || 0;
  my $NAS_ID         = $attr->{NAS_ID};              # line->[0];
  my $MNG_PASSWORD   = $attr->{MNG_PASSWORD};        # line->[11];
  my $MNG_HOST       = $attr->{MNG_HOST};            # $line->[9];
  my $RAD_PAIRS      = $attr->{RAD_PAIRS};           #$line->[12];
  my $SNMP_COMMUNITY = "$MNG_PASSWORD\@$MNG_HOST";

  my $debug_output = '';
  my $list         = $Snmputils->snmputils_nas_ipmac(
    {
      NAS_ID    => $NAS_ID,
      PG        => 0,
      PAGE_ROWS => 100000,
      DISABLE   => 0
    }
  );

  if ($Snmputils->{TOTAL} > 0) {
    $RAD_PAIRS =~ /Assign-Ports=\"(.+)\"/;
    my $ports = $1 || '';
    my $SWICH_INFO = snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

    if (!$SWICH_INFO->{version}) {
      $debug_output .= "Unknow version\n" if ($debug > 1);
      next;
    }

    my ($ACTIVE_MAC, $BLOCK_MAC) = snmputils_dlink_pb_list(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        SWITCH_INFO    => $SWITCH_INFO,
      }
    );

    my %SERVER_MAC    = ();    #Now active in server
    my %MUST_ACTIVATE = ();    #Need to be active
    my %ACTIVATE_IP_PORT = (); #Check ip port
    if ($ACTIVE_MAC->{MAC}) {
      # IP -> MAC
      %SERVER_MAC = %{ $ACTIVE_MAC->{MAC} };
    }

    foreach my $line (@$list) {
      my $user_ports = $ports;
      my @user_ports_arr =  split(/,/, $ports);
      if ($line->[7]) {
        $user_ports = $line->[7];
        @user_ports_arr =  split(/,/, $line->[7]);
      }

      $debug_output .= "$line->[0], UID: $line->[1] IP: $line->[2] MAC: $line->[3] PORT: $user_ports\n" if ($debug > 2);

      if ($line->[4] >= $conf{SNMPUTILS_BINDING_DEPOSIT}) {
        $MUST_ACTIVATE{ $line->[3] } = "$line->[2]:$user_ports";
        $ACTIVATE_IP{ $line->[2] } = \@user_ports_arr;
      }
      else {
        $debug_output .= " Negative deposit\n" if ($debug > 2);
      }
    }

    while (my ($ip, $mac) = each %SERVER_MAC) {
    	$mac = uc($mac);
      $debug_output .= "IP: $ip MAC: $mac " if ($debug > 0);
      if ($MUST_ACTIVATE{$mac} && in_array($ACTIVE_MAC{ACTIVE}{$ip}, $ACTIVATE_IP{ $ip }) ) {
        delete $MUST_ACTIVATE{$mac};
        delete $SERVER_MAC{$ip};
        $debug_output .= " Skip...\n" if ($debug > 0);
      }
      else {
        if ($debug < 3) {
          my $message = snmputils_dlink_pb_del(
            {
              SNMP_COMMUNITY => $SNMP_COMMUNITY,
              DEL            => $ip,
              SWITCH_INFO    => $SWITCH_INFO,
              MAC            => $mac,
              IP             => $ip,
              DEBUG          => $debug
            }
          );
        }
        $debug_output .= " Delete\n" if ($debug > 0);
      }
    }

    $debug_output .= "Add to server:\n" if ($debug > 0);
    while (my ($mac, $ip_port) = each %MUST_ACTIVATE) {
    	$mac = uc($mac);
      $debug_output .= "$ip_port, $mac\n" if ($debug > 0);
      my ($ip, $user_ports) = split(/:/, $ip_port, 2);

      if ($debug < 3) {
        my $message = snmputils_dlink_pb_add(
          {
            SNMP_COMMUNITY => $SNMP_COMMUNITY,
            IP             => $ip,
            PORT_ID        => ($user_ports ne '') ? $user_ports : $ports,
            MAC            => $mac,
            SWITCH_INFO    => $SWITCH_INFO,
            ACL_IP_MAC     => $conf{SNMPUTILS_DLINK_ACL_TYPE}
          }
        );
        $debug_output .= "! $message\n";
      }
    }

    #Active ports

    my @ports_arr = split(/,/, $ports);
    $debug_output .= "Active port: " if ($debug > 1);
    foreach my $port (@ports_arr) {
      if ($debug < 3) {
        my $message = snmputils_dlink_pb_state(
          {
            SNMP_COMMUNITY => $SNMP_COMMUNITY,
            STATE          => 2,
            PORT           => $port,
            SWITCH_INFO    => $SWITCH_INFO,
            DEBUG          => $debug
          }
        );
      }
      $debug_output .= "$port," if ($debug > 1);
    }

    $debug_output .= "\n";

    #Unblock ports
    while (my ($mac, $val) = each %$BLOCK_MAC) {
    	$mac = uc($mac);
      my $message = snmputils_dlink_pb_del(
        {
          SNMP_COMMUNITY => $SNMP_COMMUNITY,
          DEL            => 'block',
          SWITCH_INFO    => $SWITCH_INFO,
          MAC            => $mac,
          DEBUG          => $debug
        }
      );
      $debug_output .= "$message\n" if ($debug > 1);
    }
  }

  if ($conf{SNMPUTILS_SAVE_CONF}) {
    snmputils_dlink_save_conf({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
  }

  $DEBUG = $debug_output;
  return $debug_output;
}

#**********************************************************
#
#**********************************************************
sub snmputils_dlink_pb_version {
  my ($attr) = @_;

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my %RESULT = ();

  $RESULT{version}        = '';
  $RESULT{SNMP_COMMUNITY} = $SNMP_COMMUNITY;
  $RESULT{oid_prefix}     = '.1.3.6.1.4.1.171.11.64.1.2.7.';
  $RESULT{oid_sufix}      = {
    'IP'     => '2.1.1',
    'MAC'    => '2.1.2',
    'PORT'   => '2.1.4',
    'ACTIVE' => '2.1.5',
    'MODE'   => '2.1.6',
    'STATE'  => '1.1.2',
    'MAKE'   => '2.1.3'
  };

  if ($RESULT{version} = snmpget($SNMP_COMMUNITY, ".1.3.6.1.2.1.1.1.0")) {

    # For 3526
    #.1.3.6.1.2.1.16.19.2.0 = "Build 4.01-B19"
    #.1.3.6.1.4.1.171.12.11.1.9.4.1.8.1 = "4.01-B19"

    if ($RESULT{version} =~ /DES-3550/) {
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.11.64.2.2.7.';
      $RESULT{firmware}   = ".1.3.6.1.2.1.16.19.2.0";
      $RESULT{firmware2}  = ".1.3.6.1.4.1.171.12.11.1.9.4.1.8.1";
    }
    elsif ($RESULT{version} =~ /DES-3828/) {
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.12.23.';

      $RESULT{oid_sufix} = {
        'STATE' => '3.2.1.2',
        'IP'    => '4.1.1.1',
        'MAC'   => '4.1.1.2',
        'MAKE'  => '4.1.1.3',
        'PORT'  => '4.1.1.4',

        'ENABLE_MODE' => '3.1.0',
        'LOGIN_MODE'  => '1.1.0',
        'ACL_IP_MAC'  => '1.2.0'
      };

      $RESULT{firmware}  = ".1.3.6.1.2.1.16.19.2.0";
      $RESULT{firmware2} = ".1.3.6.1.4.1.171.12.11.1.9.4.1.8.1";
    }
    elsif ($RESULT{version} =~ /DES-3828DC/) {
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.11.69.2.2.7.';
    }
    elsif ($RESULT{version} =~ /DES-3828P/) {
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.11.69.3.2.7.';
    }
    elsif ($RESULT{version} =~ /DES-3852/) {
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.11.69.4.2.7.';
    }
    elsif ($RESULT{version} =~ /DES-30/) {

      # snmpset -v 2c -c private 10.234.1.16
      #1.3.6.1.4.1.171.12.23.4.1.1.2.10.10.65.54 x 000000000001
      #1.3.6.1.4.1.171.12.23.4.1.1.3.10.10.65.54 i 4
      #1.3.6.1.4.1.171.12.23.4.1.1.4.10.10.65.54 x 0000000000000000
      #snmpset -v 2c -c private 10.234.1.12 1.3.6.1.4.1.171.12.23.4.1.1.3.10.10.65.55 i 4 #1.3.6.1.4.1.171.12.23.4.1.1.2.10.10.65.55 x 000000000001 #1.3.6.1.4.1.171.12.23.4.1.1.4.10.10.65.55 x 00 00 00 00 00 00 00 00

      #iso.3.6.1.4.1.171.12.23.4.1.1.2.10.10.65.54 = Hex-STRING: 00 00 00 00 00 01
      #iso.3.6.1.4.1.171.12.23.4.1.1.3.10.10.65.54 = INTEGER: 4
      #iso.3.6.1.4.1.171.12.23.4.1.1.4.10.10.65.54 = Hex-STRING: 00 00 00 00 00 00 00 00
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.12.23.';
      $RESULT{oid_sufix}  = {
        'STATE' => '3.2.1.2',
        'IP'    => '4.1.1.1',
        'MAC'   => '4.1.1.2',
        'MAKE'  => '4.1.1.3',
        'PORT'  => '4.1.1.4'
      };
    }
    elsif ($RESULT{version} =~ /DES-32/) {

      # snmpset -v 2c -c private 10.234.1.16
      #1.3.6.1.4.1.171.12.23.4.1.1.2.10.10.65.54 x 000000000001
      #1.3.6.1.4.1.171.12.23.4.1.1.3.10.10.65.54 i 4
      #1.3.6.1.4.1.171.12.23.4.1.1.4.10.10.65.54 x 0000000000000000
      #iso.3.6.1.4.1.171.12.23.4.1.1.2.10.10.65.54 = Hex-STRING: 00 00 00 00 00 01
      #iso.3.6.1.4.1.171.12.23.4.1.1.3.10.10.65.54 = INTEGER: 4
      #iso.3.6.1.4.1.171.12.23.4.1.1.4.10.10.65.54 = Hex-STRING: 00 00 00 00 00 00 00 00
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.12.23.';
      $RESULT{oid_sufix}  = {
        'STATE' => '3.2.1.2',
        'IP'    => '4.1.1.1',
        'MAC'   => '4.1.1.2',
        'MAKE'  => '4.1.1.3',
        'PORT'  => '4.1.1.4'
      };
    }
    elsif ($RESULT{version} =~ /DGS-36/) {
      $RESULT{oid_prefix} = '.1.3.6.1.4.1.171.12.23.';
      $RESULT{oid_sufix}  = {
        'STATE' => '3.2.1.2',
        'IP'    => '4.1.2.1',
        'MAC'   => '4.1.2.2',
        'MAKE'  => '4.1.2.4',
        'PORT'  => '4.1.2.3',

        'ENABLE_MODE' => '3.2.1.2',
        'LOGIN_MODE'  => '1.2.0',
        'ACL_IP_MAC'  => '1.1.0'
      };
    }
    elsif ($RESULT{version} =~ /DES-1210/) {
      $RESULT{save_conf}  = '.1.3.6.1.4.1.171.10.75.15.1.10.0';
      $RESULT{oid_prefix} = '1.3.6.1.4.1.171.10.75.15.14.4.';
      $RESULT{oid_sufix}  = {

        #'STATE'  => '5',
        'IP' => '5.1.5',

        #'MAC'   => '4.1.2.2',
        'MAKE' => '5.1.5',
        'PORT' => '5.1.3',

        'ENABLE_MODE' => '1.0',
        'LOGIN_MODE'  => '2.0',
        'ACL_IP_MAC'  => '3.0'
      };
    }
    else {
      $RESULT{firmware}  = ".1.3.6.1.2.1.16.19.2.0";
      $RESULT{firmware2} = ".1.3.6.1.4.1.171.12.11.1.9.4.1.8.1";
    }

    $RESULT{firmware}  = snmpget($SNMP_COMMUNITY, $RESULT{firmware})  if ($RESULT{firmware});
    $RESULT{firmware2} = snmpget($SNMP_COMMUNITY, $RESULT{firmware2}) if ($RESULT{firmware2});
  }
  else {
    print "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
    return 0;
  }

  #Get ports state
  my @result_ports = ();
  if ($RESULT{oid_sufix}{STATE}) {
    @result_ports = &snmpwalk("$SNMP_COMMUNITY", $RESULT{oid_prefix} . "$RESULT{oid_sufix}{STATE}");
  }
  $RESULT{PORT_STATE} = \@result_ports;

  return \%RESULT;
}

#**********************************************************
# Save dlink config
#**********************************************************
sub snmputils_dlink_save_conf {
  my ($attr) = @_;
  my $message = '';

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $sw_info = $attr->{SWITCH_INFO} || snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  $SNMP_COMMUNITY .= ':167:2:1';

  #Save config
  my $oid = '1.3.6.1.4.1.171.12.1.2.6.0';
  $message = "$oid => 4\n";
  if (snmpset($SNMP_COMMUNITY, $oid, "integer", "3")) {
    $message .= " Ok\n";
  }
  else {
    $message .= "Error: Can't save config\n";
  }

  return $message;
}

#**********************************************************
#
#**********************************************************
sub snmputils_dlink_pb_add {
  my ($attr) = @_;
  my $message = '';

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';

  my $sw_info   = $attr->{SWITCH_INFO} || snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
  my $ip        = $attr->{IP}          || '0.0.0.0';
  my $port_list = $attr->{PORT_ID}     || '';
  my $mac       = $attr->{MAC}         || 0;
  my $oid_prefix  = $sw_info->{oid_prefix};
  my %oid_sufix   = %{ $sw_info->{oid_sufix} };
  my @snmp_values = ();

  # 1228
  if ($sw_info->{version} =~ /DES-1210/) {

    #	  5.	Create IMP Entry. For example, create a entry for 192.168.100.99 with MAC 02-23-45-67-89-01
    #     1.3.6.1.4.1.171.10.75.15.14.4.5.1.5.192.168.1.1.2.35.69.103.137.1 (ipMacPortBindingRowStatus) set to 5 (create and wait)
    #    P.S MAC must transform from hex to interger
    #    C:\>snmpset -v2c -c private 192.168.1.1 1.3.6.1.4.1.171.10.75.15.14.4.5.1.5.192.168.1.1.2.35.69.103.137.1 i 5

    $port_list =~ s/ //g;
    my @get_port_arr = split(/,/, $port_list);
    my @port_array = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    $port_count = 26;
    foreach my $id (@get_port_arr) {
      $port_array[ $id - 1 ] = 1;
    }

    my $unpack_      = "H2H2H2H2";
    my @ar           = unpack("$unpack_", pack("B48", join("", @port_array)));
    my $port_binding = '';
    foreach my $c (@ar) {
      $port_binding .= chr(hex($c));
    }

    my $mac_dec = mac2dec($mac);
    push @snmp_values, $oid_prefix . $oid_sufix{IP} . ".$ip.$mac_dec", "integer", "5";
    if (snmpset($SNMP_COMMUNITY, @snmp_values)) {
    }
    @snmp_values = ($oid_prefix . $oid_sufix{PORT} . ".$ip.$mac_dec", "string", "$port_binding");
    if (snmpset($SNMP_COMMUNITY, @snmp_values)) {
    }
    @snmp_values = ($oid_prefix . $oid_sufix{MAKE} . ".$ip.$mac_dec", "integer", "1");
    if (snmpset($SNMP_COMMUNITY, @snmp_values)) {
      $message .= " Ok\n";
    }

    if ($sw_info->{save_conf}) {
      snmpset($SNMP_COMMUNITY, $sw_info->{save_conf}, 'integer', 1);
    }

    return $message;
  }

  # 1.  IP- :
  my $oid = $oid_prefix . $oid_sufix{MAKE} . ".$ip";
  if ($sw_info->{version} !~ /DES-32/) {
    $message .= "$oid => 4\n";
    if (snmpset($SNMP_COMMUNITY, $oid, "integer", "4")) {
      $message .= " Ok\n";
    }
    push @snmp_values, $oid, "integer", "4";
  }

  # 3.  MAC- (AA-BB-CC-DD-EE-FF) :
  my @mac_arr = split(/:|-/, $mac);
  $mac = '';
  foreach my $c (@mac_arr) {
    $mac .= chr(hex($c));
  }

  $message .= "$oid_prefix$oid_sufix{MAC}.$ip => " . unpack("H*", $mac) . "\n";
  if ($sw_info->{version} !~ /DES-32/) {
    if (snmpset($SNMP_COMMUNITY, $oid_prefix . $oid_sufix{MAC} . ".$ip", "string", "$mac")) {
      $message .= "Ok\n";
    }
    else {
      print "MAC: '' $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
    }
  }

  push @snmp_values, $oid_prefix . $oid_sufix{MAC} . ".$ip", "string", "$mac";

  # 2.     :
  #Convert to D-Link port value
  my $port_count = $#{ $sw_info->{PORT_STATE} };
  $port_list =~ s/ //g;

  my @get_port_arr = split(/,/, $port_list);
  my @port_array = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

  $port_count = 30;
  foreach my $id (@get_port_arr) {
    if ($sw_info->{version} =~ /DES-3052/) {
      $port_array[ $id - 1 ] = 1;
    }
    elsif ($sw_info->{version} =~ /DES-30/) {
      $port_array[ $port_count + 2 - $id ] = 1;
    }
    else {
      $port_array[ $id - 1 ] = 1;
    }
  }

  my $unpack_ = "H2H2H2H2";
  if ($sw_info->{version} =~ /3550/) {
    $unpack_ = "H2H2H2H2H2H2H2";
  }
  elsif ($sw_info->{version} =~ /3052/) {
    $unpack_ = "H2H2H2H2H2H2H2H2";
  }
  elsif ($sw_info->{version} =~ /32/) {
    $unpack_ = "H2H2H2H2H2H2H2H2";
  }

  my @ar = unpack("$unpack_", pack("B48", join("", @port_array)));
  my $port_binding = '';
  foreach my $c (@ar) {
    $port_binding .= chr(hex($c));
  }

  $message .= $oid_prefix . $oid_sufix{PORT} . ".$ip => " . join(':', @ar) . "\n";
  if ($sw_info->{version} !~ /DES-32/) {
    if (snmpset($SNMP_COMMUNITY, $oid_prefix . $oid_sufix{PORT} . ".$ip", "string", "$port_binding")) {
      $message .= "Ok\n";
    }
    else {
      print "PORT: $oid_prefix / $oid_sufix{PORT} / $ip => " . join(':', @ar) . "\n";
      print "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
    }
  }
  push @snmp_values, $oid_prefix . $oid_sufix{PORT} . ".$ip", "string", "$port_binding";

  # 4.    IP MAC Port Binding (ARP / ACL):
  if ($oid_sufix{MODE}) {
    my $mode = (defined($attr->{ACL_IP_MAC})) ? int($attr->{ACL_IP_MAC}) : 1;
    if ($sw_info->{version} =~ /DES-3526/) { $mode = $mode; }
    $message .= $oid_prefix . $oid_sufix{MODE} . ".$ip => $mode\n";

    if (snmpset($SNMP_COMMUNITY, $oid_prefix . $oid_sufix{MODE} . ".$ip", "integer", $mode)) {
      $message .= "Ok\n";
    }
    push @snmp_values, $oid_prefix . $oid_sufix{MODE} . ".$ip", "integer", $mode;
  }

  # 5.  IP-MAC-Port Binding   :
  foreach my $port (@get_port_arr) {
    $message .= $oid_prefix . $oid_sufix{STATE} . ".$port => 2\n";
    if (snmpset($SNMP_COMMUNITY, $oid_prefix . $oid_sufix{STATE} . ".$port", "integer", "2")) {
      $message .= "Ok\n";
    }
  }

  if ($sw_info->{version} =~ /DES-3052/) {

  }
  elsif ($sw_info->{version} =~ /DES-30|DES-32/) {
    push @snmp_values, $oid, "integer", "4";

    print "=> $oid\n";
    if ($sw_info->{version} =~ /DES-32/) {
      if (snmpset($SNMP_COMMUNITY, @snmp_values)) {
        $message .= " Ok\n";
      }
      else {
        print $html->pre("$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg");
      }
    }
    elsif (snmpset($SNMP_COMMUNITY, $oid, "integer", "4")) {
      $message .= " Ok\n";
    }
  }

  return $message;
}

#**********************************************************
#
#**********************************************************
sub snmputils_dlink_pb_state {
  my ($attr) = @_;

  my $message        = '';
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $sw_info        = $attr->{SWITCH_INFO} || snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  # 5.  IP-MAC-Port Binding   :
  $message .= $sw_info->{oid_prefix} . $sw_info->{oid_sufix}{STATE} . ".$attr->{PORT} => $attr->{STATE}\n";
  if (snmpset($SNMP_COMMUNITY, $sw_info->{oid_prefix} . $sw_info->{oid_sufix}{STATE} . ".$attr->{PORT}", "integer", "$attr->{STATE}")) {
    $message .= "Ok\n";
  }
  else {
    $message .= "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
  }

  return $message;
}

#**********************************************************
#
#**********************************************************
sub snmputils_dlink_pb_del {
  my ($attr) = @_;

  my $message        = '';
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $sw_info        = $attr->{SWITCH_INFO} || snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  my $oid_prefix = $sw_info->{oid_prefix};
  my %oid_sufix  = %{ $sw_info->{oid_sufix} };
  my @snmp_cmd   = ();

  if ($attr->{DEL} eq 'block') {
    push @snmp_cmd, $oid_prefix . "1.$attr->{MAC}", "integer", "3";
  }

  #delete from binding list
  else {
    if ($sw_info->{version} =~ /DES-1210/) {
      $attr->{DEL} .= '.' . mac2dec($attr->{MAC});
    }
    push @snmp_cmd, $oid_prefix . $oid_sufix{MAKE} . ".$attr->{DEL}", "integer", "6";
  }

  snmpset($SNMP_COMMUNITY, @snmp_cmd);
  if ($SNMP_Session::suppress_warnings) {
    $message = "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
  }
  else {
    $message = "$_DELETED $attr->{DEL}";
  }

  return $message;
}

#**********************************************************
#
#**********************************************************
sub mac2dec {
  my ($mac) = @_;

  my @mac_val_arr = split(':', $mac);
  my @mac_dec_arr = ();
  foreach my $val (@mac_val_arr) {
    push @mac_dec_arr, hex($val);
  }
  my $mac_dec = join('.', @mac_dec_arr);
  return $mac_dec;
}

#**********************************************************
#
#**********************************************************
sub snmputils_dlink_pb_list {
  my ($attr) = @_;

  my $debug = $attr->{DEBUG} || 0;

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $SWITCH_INFO = $attr->{SWITCH_INFO} || snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  my %PREFIX = (
    1 => 'IP',
    2 => 'MAC',
    4 => 'PORT',
    5 => 'ACTIVE',
    6 => 'MODE'
  );

  my %info       = ();
  my %BLOCK_HASH = ();
  if (!$SWITCH_INFO->{oid_prefix}) {
    print "No swich info '$attr->{SNMP_COMMUNITY}'\n";
    return 0;
  }

  $SWITCH_INFO->{oid_prefix} =~ s/\.$//;

  #Full list
  $SNMP_Session::errmsg = undef;
  if ($debug > 4) {
    print "COMUNITY: $SNMP_COMMUNITY OID: '$SWITCH_INFO->{oid_prefix}'\n";
  }
  my @result = &snmpwalk("$SNMP_COMMUNITY", $SWITCH_INFO->{oid_prefix});
  if ($SNMP_Session::errmsg) {
    print "OID: '$SWITCH_INFO->{oid_prefix}'" . $html->br() . "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg\n";
    return 0;
  }

  print "OID Prefix: $SWITCH_INFO->{oid_prefix} / $SWITCH_INFO->{oid_sufix}{STATE}\n" if ($debug > 0);

  my $expr_val = chr(0) . "-" . chr(255);
  my $unpack_  = "H2H2H2H2";
  if ($SWITCH_INFO->{version} =~ /3550/ || $SWITCH_INFO->{version} =~ /3052/) {
    $unpack_ = "H2H2H2H2H2H2H2";
  }
  elsif ($SWITCH_INFO->{version} =~ /3200/) {
    $unpack_ = "H2H2H2H2H2H2H2H2";
  }

  foreach my $line (@result) {
    print $html->br() . "$line => " if ($debug > 0);

    #Blocked address
    if ($line =~ /^[\d\.]{0,2}\d\.\d\.(\d)\.\d+\.(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(.+)/) {

      #       MAC / 2 -> MAC
      $BLOCK_HASH{$2}{$1} = $3;
      print "Block" . $html->br() if ($debug > 0);
    }

    #Binding Address 1210
    #1.5. 213.169.84.100 .2.35.69.103.137.1
    elsif ($line =~ /^\d\.\d.(\d).(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\.(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}):(.+)/g) {
      my $state = $1;
      my $ip    = $2;
      my $mac   = $3;
      my $port  = $4;

      if ($state == 3) {
        my $string = unpack("B*", $port);
        if ($debug > 0) {
          my $hex_val = join(':', unpack("H2H2H2H2", pack("B48", $string)));
          print "IP: $ip PORT: $hex_val ($string)<BR>\n";
        }

        my $multi_ports = '';
        while ($string =~ m/1/g) {
          $port = pos($string);
          $multi_ports .= ",$port";
          push @{ $info{PORT}{$port} }, $ip;
        }
        $info{MULTIPORTS}{$ip} = "$multi_ports";
        my @mac_hex_arr = ();
        foreach my $val (split(/\./, $mac)) {
          push @mac_hex_arr, sprintf('%.2x', $val);
        }
        $info{MAC}{$ip} = uc(join(':', @mac_hex_arr));
      }
      elsif ($state == 5) {
        $info{ACTIVE}{$ip} = $port + 1;
      }
    }

    #Binding Address
    elsif ($line =~ /^[\d\.]{0,2}\d\.\d\.(\d)\.(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}):([$expr_val]+)/g) {
      print "=> $1 / $2 / $3 " . $html->br() if ($debug > 0);

      #Port
      if ($1 == 4) {
        my $port = $3;
        my $ip   = $2;

        my $string = unpack("B48", $port);
        if ($debug > 0) {
          my $hex_val = join(':', unpack("$unpack_", pack("B48", $string)));
          print "IP: $ip PORT: $hex_val ($string)<BR>\n";
        }

        my $multi_ports = '';
        while ($string =~ m/1/g) {
          if ($SWITCH_INFO->{version} =~ /DES-3052/) {
            $port = pos($string);
          }
          elsif ($SWITCH_INFO->{version} =~ /DES-30/) {
            $port = 33 - pos($string);
          }
          else {
            $port = pos($string);
          }

          $multi_ports .= ",$port";
          push @{ $info{PORT}{$port} }, $ip;
        }

        $info{MULTIPORTS}{$2} = "$multi_ports";    #if ($count>1);
      }
      elsif ($1 == 2) {
        if ($debug > 0) {
          print "IP: $2 MAC: $3" . $html->br();
        }
        $info{MAC}{$2} = uc(join(':', unpack("H2H2H2H2H2H2", $3)));
      }
      elsif ($PREFIX{$1}) {
        $info{ $PREFIX{$1} }{$2} = $3;
      }
    }
  }

  return \%info, \%BLOCK_HASH;
}

#**********************************************************
# http://www.dlink.ru/technical/faq_hub_switch_100.php
#    IP-MAC-Port Binding  SNMP   DES-38XX  DES-35XX
#**********************************************************
sub snmputils_dlink_ip_mac_port {
  my ($attr) = @_;

  my $debug          = $FORM{DEBUG}            || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $message        = '';

  if ($FORM{TEST}) {
    my $info = snmputils_dlink_pb({ DEBUG => $FORM{DEBUG} });
    $html->pre($info);
    return 0;
  }
  elsif ($FORM{UPDATE}) {
    $Nas->info({ NAS_ID => $FORM{NAS_ID} });

    my %CONF_HASH = (
      NAS_ID       => $Nas->{NAS_ID},
      MNG_PASSWORD => $Nas->{NAS_MNG_PASSWORD},
      MNG_HOST     => $Nas->{NAS_IP},
      RAD_PAIRS    => $Nas->{NAS_RAD_PAIRS},
      DEBUG        => $debug
    );

    my $info = snmputils_dlink_pb({%CONF_HASH});
    $html->pre($info);
  }

  if ($SNMP_COMMUNITY eq '@') {
    $html->message('err', $_ERROR, 'No SNMP community');
    return 0;
  }

  my $SWITCH_INFO = snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  my $oid_prefix   = $SWITCH_INFO->{oid_prefix};
  my %MAIN_OPTIONS = (
    enable_mode => $oid_prefix . (($SWITCH_INFO->{oid_sufix}{ENABLE_MODE}) ? $SWITCH_INFO->{oid_sufix}{ENABLE_MODE} : '4.0'),    # enable_mode
    loging_mode => $oid_prefix . (($SWITCH_INFO->{oid_sufix}{LOGIN_MODE})  ? $SWITCH_INFO->{oid_sufix}{LOGIN_MODE}  : '5.0'),    # Loging
    acl_ip_mac  => $oid_prefix . (($SWITCH_INFO->{oid_sufix}{ACL_IP_MAC})  ? $SWITCH_INFO->{oid_sufix}{ACL_IP_MAC}  : '6.0')     # ACL IP MAC
  );

  $table = $html->table(
    {
      width      => '400',
      cols_align => [ 'left', 'right' ],
      rows       => [ [ "VERSION:", $html->b($SWITCH_INFO->{version}) ], [ "FIRMWARE", $SWITCH_INFO->{firmware} ], [ "FIRMWARE2", $SWITCH_INFO->{firmware2} ] ],
      ID         => 'SNMPUTILS_SWITCH_VERSION'
    }
  );
  print $table->show();

  if ($FORM{add}) {
    my $message = snmputils_dlink_pb_add(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        IP             => $FORM{IP},
        PORT_ID        => $FORM{PORT_ID},
        MAC            => $FORM{MAC},
        SWITCH_INFO    => $SWITCH_INFO,
        ACL_IP_MAC     => $FORM{ACL_IP_MAC},
        DEBUG          => $debug
      }
    );
    print $html->message('info', $_INFO, "$message");
  }
  elsif ($FORM{state}) {
    my $message = snmputils_dlink_pb_state(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        STATE          => $FORM{state},
        PORT           => $FORM{PORT},
        SWITCH_INFO    => $SWITCH_INFO,
        DEBUG          => $debug
      }
    );
    $SWITCH_INFO = snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
    print $html->message('info', $_INFO, "$message");
  }
  elsif ($FORM{MAIN_CONF}) {

    if (snmpset($SNMP_COMMUNITY, "$MAIN_OPTIONS{$FORM{MAIN_CONF}}", "integer", "$FORM{key}")) {
      $message .= "Ok\n";
    }

    print $html->message('info', $_INFO, "$FORM{MAIN_CONF} $MAIN_OPTIONS{$FORM{MAIN_CONF}} $message");
  }
  elsif ($FORM{del}) {
    my $message = snmputils_dlink_pb_del(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        DEL            => $FORM{del},
        SWITCH_INFO    => $SWITCH_INFO,
        MAC            => $FORM{MAC},
        IP             => $FORM{IP},
        DEBUG          => $debug
      }
    );

    print $html->message('info', $_DELETED, "$message");
  }

  #Port binding enable mode
  my %THREE_MODE = (
    1 => $_OTHER,
    2 => $_ENABLE,
    3 => $_DISABLE
  );

  my $MAIN_VALUE = ();
  my $table      = $html->table(
    {
      width      => '100%',
      border     => 1,
      cols_align => [ 'left', 'center' ],
    }
  );

  while (my ($key, $value) = each %MAIN_OPTIONS) {
    $MAIN_VALUE{$key} = snmpget("$SNMP_COMMUNITY", "$value") || 0;
    if (!$MAIN_VALUE{$key}) {
      $html->message("info", $_INFO, "'$key':$value  $_NOT_SUPPORT");
    }
    else {
      $table->addrow($key, $THREE_MODE{ int($MAIN_VALUE{$key}) }, $html->button(($MAIN_VALUE{$key} != 2) ? $_ENABLE : $_DISABLE, "index=$index&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1&MAIN_CONF=$key&key=" . (($MAIN_VALUE{$key} != 2) ? 2 : 3), { BUTTON => 1 }));
    }
  }

  print $table->show();

  my $pages_qs = "&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1&";
  $pages_qs .= ($debug) ? "DEBUG=$debug" : '';

  #Port section
  $table = $html->table(
    {
      width      => '100%',
      caption    => "IP-MAC-Port Binding",
      border     => 1,
      title      => [ "$_USER", "$_PORT", "$_STATE", "IP", "MAC", "$_STATUS", "_MODE", "-", "-" ],
      cols_align => [ 'left', 'left', 'center', 'right', 'right', 'right', 'right', 'center', 'center', 'center' ],
      qs         => $pages_qs,
      ID         => 'IP-MAC-Port Binding'
    }
  );

  my @ports = ();
  my %MODES = (0 => 'ARP', 1 => 'ACL');

  my ($ACTIVE_MAC, $BLOCK_MAC) = snmputils_dlink_pb_list(
    {
      SNMP_COMMUNITY => $SNMP_COMMUNITY,
      SWITCH_INFO    => $SWITCH_INFO,
      DEBUG          => $debug
    }
  );

  foreach my $line (@{ $SWITCH_INFO->{PORT_STATE} }) {
    my ($port, $state) = split(/:/, $line, 2);
    push @ports, $port;

    $table->addtd(
      $table->td('-'),
      $table->td($port, { rowspan => 1 }),
      $table->td($THREE_MODE{$state}, { bgcolor => ($state == 2) ? '#00FF00' : $_COLORS[1], rowspan => 1 }),
      $table->td(''),
      $table->td(''),
      $table->td(''),
      $table->td(''),
      $table->td($html->button(($state == 2) ? $THREE_MODE{3} : $THREE_MODE{2}, "NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1&index=$index&PORT=$port&state=" . (($state == 2) ? 3 : 2), { BUTTON => 1 })),
      $table->td('-')

      #$table->td($html->button($_DEL, "index=$index&del=$ip_arr[0]&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1"))
    );
  }

  #My multiports  section
  my $binding;

  if ($FORM{GET_USERS}) {
    my $IDS = '';
    while (my ($ip, $mac) = each %{ $ACTIVE_MAC->{MAC} }) {
      $IDS .= "'$mac',";
    }

    while (my ($mac_dec, $value) = each %$BLOCK_MAC) {
      my $mac = join(':', unpack("H2H2H2H2H2H2", $BLOCK_MAC->{$mac_dec}{2}));
      $IDS .= "'$mac',";
    }

    chop($IDS);
    $binding = snmputils_get_users({ IDS => "$IDS" });
  }

  $table->td($port, { colspan => 9, bgcolor => $_COLORS[0] });

  while (my ($ip, $ports) = each %{ $ACTIVE_MAC->{MULTIPORTS} }) {
    if ($binding->{ $ACTIVE_MAC->{MAC}{"$ip"} }) {
      my ($name, $uid, $deposit, $status_val) = split(/:/, $binding->{ $ACTIVE_MAC->{MAC}{"$ip"} }, 4);
      $ACTIVE_MAC->{LOGIN_URL}{"$ip"} = $html->button("$name", "index=15&UID=$uid");
      $ACTIVE_MAC->{LOGIN}{"$ip"}     = "$name";
      $ACTIVE_MAC->{DEPOSIT}{"$ip"}   = $deposit;
      $ACTIVE_MAC->{STATUS}{"$ip"}    = $status_val;
    }
    else {
      $ACTIVE_MAC->{LOGIN}{"$ip"} = '-';
    }
  }

  my @entries = ();
  my $sort = $FORM{sort} || 1;

  my %SORT_COLUMNS = (
    1 => 'LOGIN',
    2 => 'MULTIPORTS',
    3 => 'IP',
    4 => 'MAC',
    5 => 'ACTIVE',
    6 => 'MODE'
  );

  while (my ($key, $value) = each %{ $ACTIVE_MAC->{ $SORT_COLUMNS{$sort} } }) {
    push @entries, "$value $key";
  }

  if ($debug > 4) {
    print "$sort / $SORT_COLUMNS{$sort} /" . $html->br();
  }

  foreach my $line (sort @entries) {
    my ($value, $ip) = split(/ /, $line, 2);

    print "value: '$value', IP: '$ip' " . $ACTIVE_MAC->{LOGIN}{"$ip"} . $html->br() if ($debug > 5);
    my $mac = $ACTIVE_MAC->{MAC}{"$ip"};
    my @arr = (
      $table->td($ACTIVE_MAC->{LOGIN_URL}{"$ip"}),
      $table->td($ACTIVE_MAC->{MULTIPORTS}{"$ip"}, { colspan => 2 }),
      $table->td($ip), $table->td($mac),
      $table->td($THREE_MODE{ $ACTIVE_MAC->{ACTIVE}{"$ip"} }),
      $table->td($MODES{ $ACTIVE_MAC->{MODE}{"$ip"} }),
      $table->td($html->button(($state == 2) ? $THREE_MODE{3} : $THREE_MODE{2}, "NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1&index=$index&PORT=$port&state=" . (($state == 2) ? 3 : 2), { BUTTON => 1 })),
      $table->td($html->button($_DEL, "index=$index&del=$ip&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1&MAC=$mac", { CLASS => 'del' }))
    );
    $table->addtd(@arr);
  }

  print $table->show();

  $Snmputils->{PORT_SEL} = $table = $html->table(
    {
      width      => '100%',
      cols_align => [ 'right', 'right', 'right', 'right', 'right', 'right', 'right' ]
    }
  );
  my @arr = ();
  foreach my $port (@ports) {
    push @arr, " $port" . $html->form_input('PORT_ID', "$port", { TYPE => 'checkbox' });
    if ($#arr != 0 && $#arr % 7 == 0) {
      $table->addrow(@arr);
      @arr = ();
    }
  }
  $table->addrow(@arr) if ($#arr > -1);
  $Snmputils->{PORT_SEL} = $table->show();

  $html->tpl_show(_include('snmputils_ip_mac_port', 'Snmputils'), { %$Snmputils, %FORM });

  $table = $html->table(
    {
      width      => '100%',
      caption    => "$_DISABLE",
      border     => 1,
      title      => [ "$_USER", "ID", "$_PORT", "MAC", "VID", "$_STATUS", '-' ],
      cols_align => [ 'left', 'left', 'center', 'right', 'right', 'right', 'right', 'center', 'center', 'center' ],
      ID         => 'DISABLED'
    }
  );

  while (my ($key, $val) = each %$BLOCK_MAC) {
    my $mac = join(':', unpack("H2H2H2H2H2H2", $BLOCK_MAC->{$key}{2}));
    my @arr = ('-', $BLOCK_MAC->{$key}{1}, $BLOCK_MAC->{$key}{4}, $mac, $BLOCK_MAC->{$key}{3}, $BLOCK_MAC->{$key}{5}, $html->button($_DEL, "index=$index&del=block&MAC=$key&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1", { CLASS => 'del' }));

    if ($binding->{$mac}) {
      my ($name, $uid) = split(/:/, $binding->{$mac});
      $arr[0] = $html->button("$name", "index=15&UID=$uid");
    }

    $table->addrow(@arr);
  }
  print $table->show();

  print $html->form_main(
    {
      CONTENT => '',
      HIDDEN  => {
        index         => "$index",
        TYPE          => $FORM{TYPE},
        NAS_HOST      => $FORM{NAS_HOST},
        NAS_COMMUNITY => $FORM{NAS_COMMUNITY},
        NAS_ID        => $FORM{NAS_ID},
        DEBUG         => $debug,
        SHOW          => 1
      },
      SUBMIT => { UPDATE => "$_REFRESH" }
    }
  );

}

#*******************************************************************
#
#
#*******************************************************************
sub snmputils_dlink_pb_monitor {
  my ($attr) = @_;

  my $debug = $attr->{DEBUG} || 0;
  my $table = $html->table(
    {
      width      => '100%',
      caption    => "$_DISABLED",
      border     => 1,
      title      => [ "$_USER", "$_DEPOSIT + $_CREDIT", "$_STATUS", "ID", "$_PORT", "MAC", "VID", '-', '-' ],
      cols_align => [ 'left', 'left', 'center', 'right', 'right', 'right', 'right', 'center', 'center', 'center' ],
      ID         => 'DISABLED'
    }
  );

  my $list;
  if ($FORM{SNMP_HOST}) {
    $list = [ '', '', '', '', '', '', '', '', '', $FORM{SNMP_HOST}, '', $FORM{SNMP_COMMUNITY}, '', '', '', '' ];
  }
  else {
    $list = $Nas->list(
      {
        PAGE_ROWS => 10000,
        SORT      => 1,
        TYPE      => dlink_pb,
        DISABLE   => 0,
      }
    );
  }

  foreach my $line (@$list) {
    $debug_output .= "NAS: $line->[0], $line->[9], $line->[11] $line->[12]\n" if ($debug > 1);

    #GET users for this NAS

    $table->{rowcolor} = $_COLORS[0];
    $table->{extra}    = "colspan='5' class='small'";
    $table->addrow("$line->[0]:" . $html->b($line->[1]) . ":$line->[3] ");
    undef($table->{rowcolor});
    undef($table->{extra});

    my $SNMP_COMMUNITY = "$line->[11]\@$line->[9]";
    my $SWICH_INFO = snmputils_dlink_pb_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

    my ($ACTIVE_MAC, $BLOCK_MAC) = snmputils_dlink_pb_list(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        SWITCH_INFO    => $SWITCH_INFO,
      }
    );

    my $binding;
    if ($FORM{GET_USERS}) {
      my $IDS = '';
      while (my ($mac_dec, $value) = each %$BLOCK_MAC) {
        my $mac = join(':', unpack("H2H2H2H2H2H2", $BLOCK_MAC->{$mac_dec}{2}));
        $IDS .= "'$mac',";
      }
      chop($IDS);
      $binding = snmputils_get_users({ IDS => "$IDS" });
    }

    while (my ($key, $val) = each %$BLOCK_MAC) {
      my $mac = join(':', unpack("H2H2H2H2H2H2", $BLOCK_MAC->{$key}{2}));
      my @arr = ('-', '-', '-', $BLOCK_MAC->{$key}{1}, $BLOCK_MAC->{$key}{4}, $mac, $BLOCK_MAC->{$key}{3}, $BLOCK_MAC->{$key}{5}, $html->button($_DEL, "index=$index&del=block&MAC=$key&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1", { CLASS => 'del' }));

      if ($binding->{$mac}) {
        my ($name, $uid, $deposit, $status_val) = split(/:/, $binding->{$mac}, 4);
        $arr[0] = $html->button("$name", "index=15&UID=$uid");
        $arr[1] = ($deposit <= 0)    ? $deposit             : $html->color_mark($deposit,             $_COLORS[6]);
        $arr[2] = ($status_val == 0) ? $status[$status_val] : $html->color_mark($status[$status_val], $_COLORS[6]);
      }
      $table->addrow(@arr);
    }
  }

  print $table->show();
}

#*******************************************************************
# http://zyxel.ru/content/support/knowledgebase/KB-1466
#
#*******************************************************************
sub snmputils_zyxel_smf_monitor {

}

#**********************************************************
#
#**********************************************************
sub snmputils_zyxel_smf_version {
  my ($attr) = @_;

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my %RESULT = ();
  $RESULT{version}        = '';
  $RESULT{SNMP_COMMUNITY} = $SNMP_COMMUNITY;

  if ($RESULT{version} = snmpget($SNMP_COMMUNITY, ".1.3.6.1.2.1.1.1.0")) {

    #$RESULT{firmware}  = snmpget($SNMP_COMMUNITY, ".1.3.6.1.2.1.16.19.2.0");
    #$RESULT{firmware2}  = snmpget($SNMP_COMMUNITY, ".1.3.6.1.4.1.171.12.11.1.9.4.1.8.1");
  }
  else {
    print "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
    return 0;
  }

  return \%RESULT;
}

#*******************************************************************
#
#*******************************************************************
sub snmputils_smf_list {

  my ($attr) = @_;

  my $debug = $attr->{DEBUG} || 0;

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  $SWITCH_INFO = '';

  #my $SWITCH_INFO = $attr->{SWITCH_INFO} || snmputils_zyxel_smf_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  my %PREFIX = (
    1 => 'IP',
    2 => 'MAC',
    4 => 'PORT',
    5 => 'ACTIVE',
    6 => 'MODE'
  );

  my %info       = ();
  my %BLOCK_HASH = ();

  #Full list
  my @result = &snmpwalk("$SNMP_COMMUNITY", '.1.3.6.1.2.1.17.7.1.3.1.1');
  print '1.3.6.1.2.1.17.7.1.3.1.1<BR>' if ($debug > 0);

  #my $expr_val = chr(0)."-".chr(255);

  foreach my $line (@result) {
    print "$line" . $html->br() if ($debug > 0);

    #Blocked address
    # Get port
    if ($line =~ /^3\.(\d{1,3})\.(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.0:(.+)/) {
      my $vlan = $1;
      my $mac  = $2;
      my $port = $3;

      if ($debug > 0) {
        print "MAC: $mac" . $html->br();
      }

      my @mac_arr = split(/\./, $mac, 6);
      my @mac_hex = ();
      foreach my $val (@mac_arr) {
        push @mac_hex, sprintf("%.2x", $val);
      }

      $info{MAC}{ $vlan . '-' . $mac } = join(':', @mac_hex);

      my $string = unpack("B32", $port);

      #my $hex_val = join(':', unpack("H2H2H2H2", pack("B32", $string)));

      if ($string =~ m/1/g) {
        $info{PORT}{ $vlan . '-' . $mac } = pos($string);
      }

    }

    #Binding Address
    elsif ($line =~ /^4\.(\d{1,3})\.(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.0:(.+)/g) {
      my $vlan  = $1;
      my $mac   = $2;
      my $state = $3;
      $info{ACTIVE}{ $vlan . '-' . $mac } = $3;
    }
  }

  return \%info, \%BLOCK_HASH;

}

#*******************************************************************
#
#*******************************************************************
sub snmputils_zyxel_smf_add {
  my ($attr) = @_;

  my $message = '';
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';

  #my $sw_info = $attr->{SWITCH_INFO} || snmputils_zyxel_smf_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  my $ip = $attr->{IP} || '0.0.0.0';

  #my $port = $attr->{PORT} || 0;
  my $port_list = $attr->{PORT_ID} || 1;
  my $mac       = $attr->{MAC}     || 0;
  my $vlan      = $attr->{VLAN}    || 0;
  my $active    = $attr->{STATE}   || 0;
  my $debug     = $attr->{DEBUG}   || 0;

  $sws = SNMPv2c_Session->open() || die "Opening SNMP_Session\n";

  # VLAN . MAC . 0
  my @mac_hex_arr = split(/:|-/, $mac);
  my @mac_dec_arr = ();
  foreach my $c (@mac_hex_arr) {
    push @mac_dec_arr, hex($c);
  }
  my $mac_dec = join('.', @mac_dec_arr);

  my $oid = '.1.3.6.1.2.1.17.7.1.3.1.1.4.' . $vlan . '.' . $mac_dec . '.0';
  $message .= "$oid => 1\n";
  if (snmpset($SNMP_COMMUNITY, $oid, "integer", "1")) {
    $message .= " Ok\n";
  }

  #Port
  $port_list =~ s/ //g;
  my @get_port_arr = split(/,/, $port_list);

  #For 24 ports
  my @port_array = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

  #For 16 ports
  #my @port_array = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

  $port_list = 1 if ($port_list eq '0');
  $port_array[ $port_list - 1 ] = 1;

  my @ar = unpack("H2H2", pack("B16", join("", @port_array)));
  my $port_binding = '';
  foreach my $c (@ar) {

    #print "$c:";
    $port_binding .= chr(hex($c));
  }

  $message .= '.1.3.6.1.2.1.17.7.1.3.1.1.3.' . $vlan . '.' . $mac_dec . '.0' . " => '$port_binding'\n";
  if (snmpset($SNMP_COMMUNITY, '.1.3.6.1.2.1.17.7.1.3.1.1.3.' . $vlan . '.' . $mac_dec . '.0', "string", "$port_binding")) {
    $message .= "Ok\n";
  }
  else {
    print "$oid => $port_binding\n";
    print "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
  }

  #ENABLE
  if ($active > 0) {
    $message .= snmputils_zyxel_smf_state(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        STATE          => 3,
        PORT_ID        => $attr->{PORT_ID},
        SWITCH_INFO    => $SWITCH_INFO,
        VLAN           => $vlan,
        MAC            => $mac,
        DEBUG          => $debug
      }
    );
  }

  return $message;
}

#*******************************************************************
# http://zyxel.ru/content/support/knowledgebase/KB-1466
#
#*******************************************************************
sub snmputils_zyxel_smf_state {
  my ($attr) = @_;

  my $ip             = $attr->{IP}             || '0.0.0.0';
  my $port_list      = $attr->{PORT_ID}        || '';
  my $mac            = $attr->{MAC}            || 0;
  my $vlan           = $attr->{VLAN}           || 0;
  my $state          = $attr->{STATE}          || 0;
  my $debug          = $attr->{DEBUG}          || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';

  my @mac_hex_arr = split(/:|-/, $mac);
  my @mac_dec_arr = ();
  foreach my $c (@mac_hex_arr) {
    push @mac_dec_arr, hex($c);
  }

  my $mac_dec = join('.', @mac_dec_arr);

  my $oid     = '.1.3.6.1.2.1.17.7.1.3.1.1.4.' . $vlan . '.' . $mac_dec . '.0';
  my $message = '';

  $message .= "$oid => $state\n";
  if (snmpset($SNMP_COMMUNITY, $oid, "integer", "$state")) {
    $message .= " Ok\n";
  }

  return $message;
}

#*******************************************************************
# http://zyxel.ru/content/support/knowledgebase/KB-1466
#
#*******************************************************************
sub snmputils_zyxel_smf {
  my ($attr) = @_;

  my $debug          = $FORM{DEBUG}            || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $message        = '';

  if ($FORM{TEST}) {
    $html->pre(snmputils_zyxel_smf({ DEBUG => $FORM{DEBUG} }));
    return 0;
  }
  elsif ($FORM{UPDATE}) {
    my $info = snmputils_zyxel_smf(
      {
        NAS_IDS => $FORM{NAS_ID},
        DEBUG   => 1
      }
    );
    $html->pre($info);
  }

  my $SWITCH_INFO = snmputils_zyxel_smf_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  $table = $html->table(
    {
      width      => '400',
      cols_align => [ 'left', 'right' ],
      rows       => [ [ "VERSION:", $html->b($SWITCH_INFO->{version}) ], [ "FIRMWARE", $SWITCH_INFO->{firmware} ], [ "FIRMWARE2", $SWITCH_INFO->{firmware2} ] ],
      ID         => 'SNMPUTILS_SWITCH_VERSION'
    }
  );
  print $table->show();

  $Snmputils->{ACTION}     = 'add';
  $Snmputils->{ACTION_LNG} = $_ADD;

  if ($FORM{add}) {
    my $message = snmputils_zyxel_smf_add(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        IP             => $FORM{IP},
        PORT_ID        => $FORM{PORT},
        MAC            => "$FORM{MAC_1}-$FORM{MAC_2}-$FORM{MAC_3}-$FORM{MAC_4}-$FORM{MAC_5}-$FORM{MAC_6}",
        SWITCH_INFO    => $SWITCH_INFO,
        VLAN           => $FORM{VLAN},
        STATE          => $FORM{ACTIVE},
        DEBUG          => $FORM{DEBUG}
      }
    );
    print $html->message('info', $_INFO, "$message");
  }
  elsif ($FORM{state}) {
    my $message = snmputils_zyxel_smf_state(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        STATE          => $FORM{state},
        PORT_ID        => $FORM{PORT},
        SWITCH_INFO    => $SWITCH_INFO,
        VLAN           => $FORM{VLAN},
        MAC            => $FORM{MAC},
        DEBUG          => $FORM{DEBUG}
      }
    );

    print $html->message('info', $_INFO, "$message");
  }
  elsif ($FORM{MAIN_CONF}) {

    if (snmpset($SNMP_COMMUNITY, "$MAIN_OPTIONS{$FORM{MAIN_CONF}}", "integer", "$FORM{key}")) {
      $message .= "Ok\n";
    }

    print $html->message('info', $_INFO, "$FORM{MAIN_CONF} $MAIN_OPTIONS{$FORM{MAIN_CONF}} $message");
  }

  #Port section
  $table = $html->table(
    {
      width      => '100%',
      caption    => "Zyxel Static MAC Forwarding",
      border     => 1,
      title      => [ "$_USER", "$_PORT", "$_STATE", "VLAN", "MAC", "$_NAME", "-", "-" ],
      cols_align => [ 'left', 'left', 'center', 'right', 'right', 'right', 'right', 'center', 'center', 'center' ],
    }
  );

  my @ports = ();
  my %MODES = (0 => 'ARP', 1 => 'ACL');

  my ($ACTIVE_MAC, $BLOCK_MAC) = snmputils_smf_list(
    {
      SNMP_COMMUNITY => $SNMP_COMMUNITY,
      SWITCH_INFO    => $SWITCH_INFO,
      DEBUG          => $FORM{DEBUG}
    }
  );

  #my multiports  section
  my $binding;

  if ($FORM{GET_USERS}) {
    my $IDS = '';
    while (my ($ip, $mac) = each %{ $ACTIVE_MAC->{MAC} }) {
      $IDS .= "'$mac',";
    }

    chop($IDS);
    $binding = snmputils_get_users({ IDS => "$IDS" });
  }

  my %STATUS = (
    1 => $_DISABLE,
    3 => $_ENABLE
  );

  my $page_arguments = '';
  while (my ($vlan_mac, $mac) = each %{ $ACTIVE_MAC->{MAC} }) {
    my ($VLAN, $m) = split(/-/, $vlan_mac, 2);
    my $state = $ACTIVE_MAC->{ACTIVE}{$vlan_mac};

    if ($FORM{NAS_ID}) {
      $page_arguments = "&NAS_ID=$FORM{NAS_ID}";
    }
    else {
      $page_arguments = "&SNMP_HOST=$FORM{SNMP_HOST}&SNMP_COMMUNITY=$FORM{SNMP_COMMUNITY}";
    }

    my @arr = (
      $table->td($ACTIVE_MAC->{PORT}{$vlan_mac}),
      $table->td($STATUS{$state}, { bgcolor => ($state == 3) ? '#00FF00' : $_COLORS[1] }),
      $table->td($VLAN),
      $table->td($ACTIVE_MAC->{MAC}{$vlan_mac}),
      $table->td($ACTIVE_MAC->{NAME}{$vlan_mac}),
      $table->td($html->button(($state == 3) ? $STATUS{1} : $STATUS{3}, "$page_arguments&TYPE=$FORM{TYPE}&SHOW=1&index=$index&VLAN=$VLAN&MAC=$ACTIVE_MAC->{MAC}{$vlan_mac}&PORT=$ACTIVE_MAC->{PORT}{$vlan_mac}&state=" . (($state == 3) ? 1 : 3), { BUTTON => 1 })),
      $table->td($html->button($_DEL, "index=$index&VLAN=$VLAN&MAC=$ACTIVE_MAC->{MAC}{$vlan_mac}$page_arguments&TYPE=$FORM{TYPE}&SHOW=1&state=2", { CLASS => 'del' }))
    );

    if ($binding->{ $ACTIVE_MAC->{MAC}{$vlan_mac} }) {
      my ($name, $uid) = split(/:/, $binding->{ $ACTIVE_MAC->{MAC}{$vlan_mac} });
      unshift @arr, $table->td($html->button("$name", "index=15&UID=$uid"));
    }
    else {
      unshift @arr, $table->td('-');
    }

    $table->addtd(@arr);
  }

  print $table->show();

  $Snmputils->{ACTIVE} = 'checked';
  $html->tpl_show(_include('snmputils_smf', 'Snmputils'), { %$Snmputils, %FORM });

}

#*******************************************************************
#
#
#*******************************************************************
sub snmputils_ciscoair {
  my ($attr) = @_;

  my $list;
  if ($FORM{'SNMP_HOST'} ne '') {
    $list = [ [ '1', '', '', $FORM{'SNMP_HOST'}, '', '', '', '', '', '', '', $FORM{'SNMP_COMMUNITY'}, '', '' ] ];
  }
  elsif ($attr->{SNMP_COMMUNITY}) {
    print $attr->{SNMP_COMMUNITY};

    my ($community, $host) = split(/@/, $attr->{SNMP_COMMUNITY}, 2);
    $FORM{'SNMP_HOST'}      = $host;
    $FORM{'SNMP_COMMUNITY'} = $community;

    $list = [ [ ($FORM{NAS_ID}) ? $FORM{NAS_ID} : '1', '', '', $host, '', '', '', '', '', '', '', $community, '', '' ] ];
  }
  else {
    $list = $Nas->list(
      {
        TYPE    => 'cisco_air',
        DISABLE => 0
      }
    );
  }

  my %fields = (

    #Info
    #cDot11ClientAddress           => '.1.3.6.1.4.1.9.9.273.1.2.1.1.1',
    cDot11ClientParentAddress    => '.1.3.6.1.4.1.9.9.273.1.2.1.1.2',
    cDot11ClientRoleClassType    => '.1.3.6.1.4.1.9.9.273.1.2.1.1.3',
    cDot11ClientDevType          => '.1.3.6.1.4.1.9.9.273.1.2.1.1.4',
    cDot11ClientRadioType        => '.1.3.6.1.4.1.9.9.273.1.2.1.1.5',
    cDot11ClientWepEnabled       => '.1.3.6.1.4.1.9.9.273.1.2.1.1.6',
    cDot11ClientWepKeyMixEnabled => '.1.3.6.1.4.1.9.9.273.1.2.1.1.7',
    cDot11ClientMicEnabled       => '.1.3.6.1.4.1.9.9.273.1.2.1.1.8',
    cDot11ClientPowerSaveMode    => '.1.3.6.1.4.1.9.9.273.1.2.1.1.9',
    cDot11ClientAid              => '.1.3.6.1.4.1.9.9.273.1.2.1.1.10',
    cDot11ClientDataRateSet      => '.1.3.6.1.4.1.9.9.273.1.2.1.1.11',
    cDot11ClientSoftwareVersion  => '.1.3.6.1.4.1.9.9.273.1.2.1.1.12',
    cDot11ClientName             => '.1.3.6.1.4.1.9.9.273.1.2.1.1.13',
    cDot11ClientAssociationState => '.1.3.6.1.4.1.9.9.273.1.2.1.1.14',
    cDot11ClientIpAddressType    => '.1.3.6.1.4.1.9.9.273.1.2.1.1.15',
    cDot11ClientIpAddress        => '.1.3.6.1.4.1.9.9.273.1.2.1.1.16',
    cDot11ClientVlanId           => '.1.3.6.1.4.1.9.9.273.1.2.1.1.17',
    cDot11ClientSubIfIndex       => '.1.3.6.1.4.1.9.9.273.1.2.1.1.18',

    #                cDot11ClientAuthenAlgorithm   => '.1.3.6.1.4.1.9.9.273.1.2.1.1.19',
    #                cDot11ClientAdditionalAuthen  => '.1.3.6.1.4.1.9.9.273.1.2.1.1.2.20',
    #                cDot11ClientDot1xAuthenAlgorithm => '.1.3.6.1.4.1.9.9.273.1.2.1.1.2.21',
    #                cDot11ClientKeyManagement     => '.1.3.6.1.4.1.9.9.273.1.2.1.1.2.22',
    #                 cDot11ClientUnicastCipher     => '.1.3.6.1.4.1.9.9.273.1.2.1.1.2.23',
    #                cDot11ClientMulticastCipher   => '.1.3.6.1.4.1.9.9.273.1.2.1.1.2.24',

    #Stats
    cDot11ClientCurrentTxRateSet => '.1.3.6.1.4.1.9.9.273.1.3.1.1.1',
    cDot11ClientUpTime           => '.1.3.6.1.4.1.9.9.273.1.3.1.1.2',
    cDot11ClientSignalStrength   => '.1.3.6.1.4.1.9.9.273.1.3.1.1.3',
    cDot11ClientSigQuality       => '.1.3.6.1.4.1.9.9.273.1.3.1.1.4',
    cDot11ClientAgingLeft        => '.1.3.6.1.4.1.9.9.273.1.3.1.1.5',
    cDot11ClientPacketsReceived  => '.1.3.6.1.4.1.9.9.273.1.3.1.1.6',
    cDot11ClientBytesReceived    => '.1.3.6.1.4.1.9.9.273.1.3.1.1.7',
    cDot11ClientPacketsSent      => '.1.3.6.1.4.1.9.9.273.1.3.1.1.8',
    cDot11ClientBytesSent        => '.1.3.6.1.4.1.9.9.273.1.3.1.1.9',
    cDot11ClientDuplicates       => '.1.3.6.1.4.1.9.9.273.1.3.1.1.10',
    cDot11ClientMsduRetries      => '.1.3.6.1.4.1.9.9.273.1.3.1.1.11',
    cDot11ClientMsduFails        => '.1.3.6.1.4.1.9.9.273.1.3.1.1.12',
    cDot11ClientWepErrors        => '.1.3.6.1.4.1.9.9.273.1.3.1.1.13',
    cDot11ClientMicErrors        => '.1.3.6.1.4.1.9.9.273.1.3.1.1.14',
    cDot11ClientMicMissingFrames => '.1.3.6.1.4.1.9.9.273.1.3.1.1.15',

    'ClientConfigInfoEntry'  => '.1.3.6.1.4.1.9.9.273.1.2.1.1.17',
    'ClientConfigInfoEntry2' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.18',
    'ClientConfigInfoEntry3' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.19',
    'ClientConfigInfoEntry4' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.20',
    'ClientConfigInfoEntry5' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.21',
    'ClientConfigInfoEntry6' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.22',
    'ClientConfigInfoEntry7' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.23',
    'ClientConfigInfoEntry8' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.24',
    'ClientConfigInfoEntry9' => '.1.3.6.1.4.1.9.9.273.1.2.1.1.25',

    #              'MAC                    => '.1.3.6.1.2.1.17.4.3.1.1.'
  );

  if ($FORM{Client}) {
    my %info = ();
    my $list = $Snmputils->snmputils_binding_list({ BINDING => $FORM{MAC}, PAGE_ROWS => 100000 });

    #cisco_air:00:11:95:e9:3b:2e
    if ($Snmputils->{TOTAL} > 0) {
      $info{LOGIN} = $html->button("$list->[0]->[0]", "index=11&UID=$list->[0]->[5]");
    }
    else {
      $info{LOGIN} = "Check binding";
    }

    my $SNMP_COMMUNITY = '';
    my $SNMP_HOST      = '';

    if ($FORM{'SNMP_HOST'}) {
      $SNMP_HOST      = $FORM{'SNMP_HOST'};
      $SNMP_COMMUNITY = $FORM{'SNMP_COMMUNITY'};
    }
    else {
      $Nas->info({ NAS_ID => $FORM{NAS_ID} });

      $SNMP_COMMUNITY = $Nas->{NAS_MNG_PASSWORD};
      $SNMP_HOST      = $Nas->{NAS_IP};
    }

    my $prefix_id = ($FORM{PREFIX_ID}) ? '.' . $FORM{PREFIX_ID} . '.' : '.1.7.119.108.97.110.119.101.112.';
    foreach my $key (keys %fields) {
      $info{$key} = snmpget("$SNMP_COMMUNITY\@$SNMP_HOST", $fields{$key} . $prefix_id . $FORM{Client});

      if ($debug > 0) {
        print "$key: $fields{$key} / $prefix_id / $FORM{Client} = $info{$key}" . $html->br();
        if ($SNMP_Session::errmsg) {
          print "$SNMP_Session::errmsg" . $html->br();
        }
      }

      $info{$key} = data_convert($key, $info{$key});
    }

    $info{MAC} = $FORM{MAC};
    $html->tpl_show(_include('snmputils_cisco_air_client_info', 'Snmputils'), \%info);
    return 0;
  }

  my @default_fields = ('cDot11ClientName', 'cDot11ClientDevType', 'cDot11ClientIpAddress', 'cDot11ClientAssociationState', 'cDot11ClientSigQuality', 'cDot11ClientSignalStrength', 'cDot11ClientUpTime', 'cDot11ClientDuplicates');

  if ($FORM{fields}) {
    @default_fields = split(/, /, $FORM{fields});
  }

  my @CAPTION = ('MAC', @default_fields, '-');

  my $binding;
  if ($FORM{GET_USERS}) {
    unshift @CAPTION, $_USERS;
  }

  $table = $html->table(
    {
      width      => '100%',
      caption    => "CISCO Aironets",
      border     => 1,
      title      => \@CAPTION,
      cols_align => [ 'left', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'center' ],
    }
  );

  my $total_sessions = 0;
  my $oid_prefix     = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.{0,1}\d{0,3}\.{0,1}\d{0,3}' . '\.{0,1}\d{0,3}\.{0,1}\d{0,3}\.{0,1}\d{0,3}\.{0,1}\d{0,3}\.{0,1}\d{0,3}';

  #Nas list
  foreach my $line (@$list) {
    my %result    = ();
    my @MAC_ARR   = ();
    my $prefix_id = '';
    my $serie     = '';
    my $firmware  = '';
    my $version   = snmpget("$line->[11]\@$line->[3]", '.1.3.6.1.2.1.47.1.1.1.1.7.1');

    if (!$SNMP_Session::errmsg) {
      $firmware = snmpget("$line->[11]\@$line->[3]", '.1.3.6.1.4.1.9.9.25.1.1.1.2.5');
      $serie    = snmpget("$line->[11]\@$line->[3]", '.1.2.840.10036.3.1.2.1.3.1');

      foreach my $field (@default_fields) {
        my @arr = snmpwalk("$line->[11]\@$line->[3]", $fields{$field});
        foreach my $line (@arr) {
          if ('.' . $line =~ /($oid_prefix)\.(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(.+)/) {
            $prefix_id = $1 if ($prefix_id eq '');
            my $sufix = $2;
            my $value = $3;
            $result{$field}{"$sufix"} = $value;
            print "Line: $line" . $html->br() . "PREFIX: $prefix_id <BR>\nNAME: $field // Sufix: $sufix / Result: $value" . $html->br() if ($debug == 1);
          }
        }
      }

      @MAC_ARR = keys %{ $result{ $default_fields[0] } };

      if ($FORM{GET_USERS}) {
        my $IDS = '';
        foreach my $mac (@MAC_ARR) {
          my @mac_arr = split(/\./, $mac);
          for (my $i = 0 ; $i <= $#mac_arr ; $i++) {
            $mac_arr[$i] = sprintf("%.2X", $mac_arr[$i]);
          }
          my $mac = join(':', @mac_arr);
          $IDS .= "'$mac',";
        }
        chop($IDS);
        $binding = snmputils_get_users({ IDS => "$IDS" });
      }
    }
    else {
      $version              = 'No response...';
      $SNMP_Session::errmsg = undef;
    }

    $table->{rowcolor} = $_COLORS[0];
    $table->{eowcolor} = $_COLORS[0];
    $table->{extra}    = "colspan='" . ($#CAPTION + 2) . "' class='small'";
    $table->addrow("$line->[0]:" . $html->b($line->[1]) . "/$version, $serie, $firmware/:$line->[3] (" . $html->button('WEB', "", { GLOBAL_URL => "http://$line->[3]", BUTTON => 1 }) . "):$_TOTAL: " . ($#MAC_ARR + 1));

    $total_sessions += $#MAC_ARR + 1;

    undef($table->{rowcolor});
    undef($table->{extra});

    foreach my $k (@MAC_ARR) {
      my @mac_arr = split(/\./, $k);
      for (my $i = 0 ; $i <= $#mac_arr ; $i++) {
        $mac_arr[$i] = sprintf("%.2X", $mac_arr[$i]);
      }
      my $mac = join(':', @mac_arr);

      my @arr = ();
      foreach my $ft (@default_fields) {

        $result{$ft}{$k} = data_convert($ft, $result{$ft}{$k});
        push @arr, $result{$ft}{$k};
      }

      my $page_params = "&NAS_ID=$line->[0]";
      if ($FORM{'SNMP_HOST'}) {
        $page_params = "&SNMP_HOST=$FORM{'SNMP_HOST'}&SNMP_COMMUNITY=$FORM{'SNMP_COMMUNITY'}";
      }
      if ($prefix_id ne '') {
        $page_params .= "&PREFIX_ID=$prefix_id";
      }

      if ($FORM{TYPE}) {
        $page_params .= "&TYPE=$FORM{TYPE}&SHOW=1";
      }

      unshift @arr, $html->button("<CODE>$mac</CODE>", "index=$index&NAS_TYPE=cisco_air&Client=$k&MAC=$mac$page_params");

      #Get binding info
      if ($FORM{GET_USERS}) {
        if ($binding->{$mac}) {
          my ($name, $uid) = split(/:/, $binding->{$mac});
          unshift @arr, $html->button("$name", "index=15&UID=$uid");
        }
        else {
          unshift @arr, '';
        }
      }

      $table->addrow(@arr, $html->button('H', "index=$index&hangup=$k", { TITLE => 'Hangup', BUTTON => 1 }));

    }

    #last;

  }

  print $table->show();

  $table = $html->table(
    {
      width      => '100%',
      rowcolor   => $_COLORS[3],
      cols_align => [ 'right', 'left', 'right', 'right', 'center' ],
      rows       => [ [ "$_TOTAL:", "$_USERS:", "$total_users", "$_SESSIONS:", "$total_sessions" ] ]
    }
  );

  print $table->show();

  snmp_form_footer(\%fields, \@default_fields, { OIDS_EXINFO => snmputils_load_mibs([ 'CISCO-SMI', 'CISCO-DOT11-IF-MIB', 'CISCO-DOT11-ASSOCIATION-MIB' ]) });
}

#***********************************************************
#
#**********************************************************
sub data_convert {
  my ($name, $data, $attr) = @_;

  my $ret = '';
  if ($attr->{OIDS_EXINFO} && $attr->{OIDS_EXINFO}{$name}{SYNTAX} eq 'MacAddress') {
    $ret = join(':', unpack("H2H2H2H2H2H2", $data));
  }

  #Cisco Section
  elsif ($name eq 'cDot11ClientIpAddress') {
    $ret = int2ip(unpack("N4", $data));
  }
  elsif ($name eq 'cDot11ClientParentAddress') {
    $ret = join(':', unpack("H2H2H2H2H2H2", $data));

    #$ret = join(':', unpack("H*", $data));
  }
  elsif ($name eq 'cDot11ClientUpTime') {
    $ret = sec2time($data, { str => 1 });
  }
  elsif ($name eq 'cDot11ClientDataRateSet') {
    my @arr = unpack("C*", $data);
    for (my $i ; $i < $#arr ; $i++) {
      $arr[$i] = $arr[$i] / 2;
    }
    $ret = join(", ", @arr) . ' Mbps';
  }
  elsif ($name eq 'cDot11ClientCurrentTxRateSet' || $name eq 'ClientCurrentTxRateSet') {
    $ret = (hex((unpack("H2", $data))) / 2) . " Mbps";
  }
  elsif ($name eq 'cDot11ClientAssociationState') {
    $ret = $association_state[$data];
  }
  else {
    $ret = $data;
  }

  return $ret;
}

#**********************************************************
#
#**********************************************************
sub snmputils_patton_dialin {

  my %fields = (

    diactIndex                  => '1',
    diactMultiIndex             => '2',
    diactState                  => '3',
    diactProtocol               => '4',
    diactAccessLevel            => '5',
    diactDSPIndex               => '6',
    diactIFIndex                => '7',
    diactLinkIndex              => '8',
    diactSlotIndex              => '9',
    diactIP                     => '10',
    diactPort                   => '11',
    diStatBadAddresses          => '12',
    diStatBadControls           => '13',
    diStatPacketTooLongs        => '14',
    diStatBadFCSs               => '15',
    diStatLocalMRU              => '16',
    diStatRemoteMRU             => '17',
    diStatLocalToPeerACCMap     => '18',
    diStatPeerToLocalACCMap     => '19',
    diStatLocalToRemoteProtComp => '20',
    diStatRemoteToLocalProtComp => '21',
    diStatLocalToRemoteACComp   => '22',
    diStatRemoteToLocalACComp   => '22',
    diStatTransmitFcsSize       => '23',
    diStatReceiveFcsSize        => '24',
    diIpOperStatus              => '25',
    diIpLocalToRemoteCompProt   => '26',
    diIpRemoteToLocalCompProt   => '27',
    diIpRemoteMaxSlotId         => '28',
    diIpLocalMaxSlotId          => '29',
    diactSessionTime            => '30',
    diactRemainingIdle          => '31',
    diactRemainingSession       => '33',
    diactNumberDialed           => '34',
    diactCallingPhone           => '35',
    diactSentOctets             => '36',
    diactReceivedOctets         => '37',
    diactSentDataFrames         => '38',
    diactReceivedDataFrames     => '39',
    diactErrorFrames            => '40',
    diactSessionStartTime       => '41',
    diactModulation             => '43',
    diactErrorCorrection        => '44',
    diactCompression            => '45',
    diactMultiLinkFlag          => '46',
    diactSymbolRate             => '48',

    diactTxSpeed => '49',
    diactRxSpeed => '50',

    diactUsername           => '56',
    diactPassword           => '57',
    diactTerminateReason    => '58',
    diactTerminateState     => '59',
    diactLocalRenegotiates  => '60',
    diactLocalRetrains      => '61',
    diactRemoteRenegotiates => '62',
    diactRemoteRetrains     => '63',
    diStatLcpRemoteMRRU     => '64',
    diStatLcpLocalMRRU      => '65',
    diStatLcpAuth           => '66',

    diStatIpFilterA => '70',
    diStatIpFilterB => '71',
    diStatIpFilterC => '72',
    diStatIpFilterD => '73',
    diStatIpFilterE => '74',
    diStatIpFilterF => '75',
    diStatIpFilterG => '76',
    diStatIpFilterH => '77',
    diStatIpFilterI => '78',
    diStatIpFilterJ => '79',

    diactForceNextHop => '67',
    diactPrimaryDNS   => '100',
    diactSecondaryDNS => '101'
  );

  snmputils_multioid_view(
    {
      FIELDS         => \%fields,
      DEFAULT_FIELDS => [ 'diactIndex', 'diactSlotIndex', 'diactUsername', 'diactState' ],
      OID_PREFIX     => '1.3.6.1.4.1.1768.5.100.1',
      NAS_TYPE       => 'patton',
      MIBS => [ 'corporat.mib', 'common.mib', 'product.mib' ]
    }
  );
}

#**********************************************************
#
#**********************************************************
sub snmputils_portmaster {

  my %fields = (
    livingstonSerialIndex             => 1,
    livingstonSerialPortName          => 2,
    livingstonSerialPhysType          => 3,
    livingstonSerialUser              => 4,
    livingstonSerialSessionId         => 5,
    livingstonSerialType              => 6,
    livingstonSerialDirection         => 7,
    livingstonSerialPortStatus        => 8,
    livingstonSerialStarted           => 9,
    livingstonSerialIdle              => 10,
    livingstonSerialInSpeed           => 11,
    livingstonSerialOutSpeed          => 12,
    livingstonSerialModemName         => 13,
    livingstonSerialIpAddress         => 14,
    livingstonSerialifDescr           => 15,
    livingstonSerialInOctets          => 16,
    livingstonSerialOutOctets         => 17,
    livingstonSerialQOctets           => 18,
    livingstonSerialModemStatus       => 19,
    livingstonSerialModemCompression  => 20,
    livingstonSerialModemProtocol     => 21,
    livingstonSerialModemRetrains     => 22,
    livingstonSerialModemRenegotiates => 23,

    #      livingstonSerialSlotId             => 24,
    #      livingstonSerialPortId             => 25
  );

  snmputils_multioid_view(
    {
      FIELDS         => \%fields,
      DEFAULT_FIELDS => [ 'livingstonSerialIndex', 'livingstonSerialUser', 'livingstonSerialIpAddress', 'livingstonSerialSessionId', 'livingstonSerialModemStatus' ],
      OID_PREFIX     => '.1.3.6.1.4.1.307.3.2.1.1.1',
      NAS_TYPE       => 'pm25',
      MIBS           => ['livingston.mib']
    }
  );
}

#**********************************************************
#
#**********************************************************
sub snmputils_mikrotik_info {

  my %fields = (
    'uptime'          => '.1.3.6.1.2.1.1.3.0',
    'total-hdd-space' => '.1.3.6.1.2.1.25.2.3.1.5.1',
    'used-hdd-space'  => '.1.3.6.1.2.1.25.2.3.1.6.1',
    'total-memory'    => '.1.3.6.1.2.1.25.2.3.1.5.2',
    'used-memory'     => '.1.3.6.1.2.1.25.2.3.1.6.2',
    'cpu-load'        => '.1.3.6.1.2.1.25.3.3.1.2.1'
  );

  my @caption = ('uptime', 'total-hdd-space', 'used-hdd-space', 'total-memory', 'used-memory', 'cpu-load');
  my $table = $html->table(
    {
      width      => '100%',
      title      => \@caption,
      cols_align => [ 'right', 'left', 'right', 'right', 'center' ],
    }
  );

  snmputils_multioid_view(
    {
      DEFAULT_FIELDS => [ 'uptime', 'total-hdd-space', 'used-hdd-space', 'total-memory', 'used-memory', 'cpu-load' ],
      NAS_TYPE       => 'Mikrotik',
      SINGLE         => \%fields
    }
  );

}

#**********************************************************
#
#**********************************************************
sub snmputils_docsis_modems {

  my %fields = (

    #docsIfCmtsCmStatusIndex               => '1',
    docsIfCmtsCmStatusMacAddress         => '2',
    docsIfCmtsCmStatusIpAddress          => '3',
    docsIfCmtsCmStatusDownChannelIfIndex => '4',
    docsIfCmtsCmStatusUpChannelIfIndex   => '5',
    docsIfCmtsCmStatusRxPower            => '6',
    docsIfCmtsCmStatusTimingOffset       => '7',
    docsIfCmtsCmStatusEqualizationData   => '8',

    docsIfCmtsCmStatusValue            => '9',
    docsIfCmtsCmStatusUnerroreds       => '10',
    docsIfCmtsCmStatusCorrecteds       => '11',
    docsIfCmtsCmStatusUncorrectables   => '12',
    docsIfCmtsCmStatusSignalNoise      => '13',
    docsIfCmtsCmStatusMicroreflections => '14'
  );

  #	docsIfCmtsCmStatusValue OBJECT-TYPE
  #        SYNTAX      INTEGER {
  #            other(1),
  #            ranging(2),
  #            rangingAborted(3),
  #            rangingComplete(4),
  #            ipComplete(5),
  #            registrationComplete(6),
  #            accessDenied(7)

  snmputils_multioid_view(
    {
      FIELDS         => \%fields,
      DEFAULT_FIELDS => [ 'docsIfCmtsCmStatusIndex', 'docsIfCmtsCmStatusMacAddress', 'docsIfCmtsCmStatusIpAddress', 'docsIfCmtsCmStatusDownChannelIfIndex', 'docsIfCmtsCmStatusUpChannelIfIndex', 'docsIfCmtsCmStatusValue' ],
      OID_PREFIX     => '1.3.6.1.2.1.10.127.1.3.3.1',
      NAS_TYPE       => 'BSR1000',
      MIBS           => ['DOCS-IF-MIB']
    }
  );

}

#**********************************************************
#
#**********************************************************
sub snmputils_multioid_view {
  my ($attr) = @_;

  my $fields         = $attr->{FIELDS};
  my @default_fields = @{ $attr->{DEFAULT_FIELDS} };
  my $oid_prefix     = $attr->{OID_PREFIX} || '';
  my $nas_type       = $attr->{NAS_TYPE} || '';

  if ($FORM{fields}) {
    @default_fields = split(/, /, $FORM{fields});
  }

  my $OIDS_EXINFO;
  if ($attr->{MIBS}) {
    $OIDS_EXINFO = snmputils_load_mibs($attr->{MIBS});
  }

  $table = $html->table(
    {
      width      => '100%',
      caption    => "$nas_type",
      border     => 1,
      title      => [ @default_fields, "-" ],
      cols_align => [ 'left', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'center' ]
    }
  );

  my $list = $Nas->list({ TYPE => $nas_type, DISABLE => 0 });

  foreach my $line (@$list) {
    my %result = ();

    if ($attr->{SINGLE}) {
      while (my ($name, $oid) = each %{ $attr->{SINGLE} }) {
        $result{$name}{0} = snmpget("$line->[11]\@$line->[3]", $oid);
      }
    }
    else {
      foreach my $field (@default_fields) {
        my @arr = ();
        if (@arr = snmpwalk("$line->[11]\@$line->[3]", $oid_prefix . '.' . $fields->{$field})) {
          my $oid = "$field - $oid_prefix/$fields->{$field}";

          if ($SNMP_Session::errmsg) {
            print $html->message('err', $_ERROR,
                "$oid"
              . $html->br()
              . "$SNMP_Session::suppress_warnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmrnings / $SNMP_Session::errmsg"
            );
            last;
          }
          foreach my $line (@arr) {
            if ($line =~ /([\d\.]+):(.+)/) {
              $result{$field}{$1} = $2;
              print "$field // $line ($1:$2) " . $html->br() if ($debug == 1);
            }
          }
        }
        else {
          print "- $field - $oid_prefix/$fields->{$field} " . $html->br() if ($debug == 1);
          print $html->message('err', $_ERROR, "No response");
          last;
        }
      }
    }

    $table->{rowcolor} = $_COLORS[0];
    $table->{extra} = "colspan='" . ($#default_fields + 2) . "' class='small'";
    $table->addrow("$line->[0]:" . $html->b($line->[1]) . ":$line->[3] ");
    $page_qs .= "&NAS_ID=$line->[0]";
    $total_sessions += $#MAC_ARR + 1;

    undef($table->{rowcolor});
    undef($table->{extra});

    my @SESSION_ARR = sort keys %{ $result{ $default_fields[0] } };

    foreach my $k (@SESSION_ARR) {
      my @arr = ();
      foreach my $ft (@default_fields) {
        $result{$ft}{$k} = data_convert($ft, $result{$ft}{$k}, { OIDS_EXINFO => $OIDS_EXINFO });
        push @arr, ($OIDS_EXINFO->{$ft}{ACCESS} eq 'read-write') ? $html->button($result{$ft}{$k}, "index=$index&change=y&SNMP_INDEX=$inst&SNMP_OID=$OIDS_HASH{$ft}$page_qs") : $result{$ft}{$k};
      }

      $table->addrow(@arr, $html->button('H', "index=$index&hangup=$k", { TITLE => 'Hangup', BUTTON => 1 }));

    }

  }

  print $table->show();
  $table = $html->table(
    {
      width      => '100%',
      rowcolor   => $_COLORS[3],
      cols_align => [ 'right', 'left', 'right', 'right', 'center' ],
      rows       => [ [ "$_TOTAL:", "$_USERS:", "$total_users", "$_SESSIONS:", "$total_sessions" ] ]
    }
  );

  print $table->show();

  snmp_form_footer($fields, \@default_fields, { OIDS_EXINFO => $OIDS_EXINFO });
}

#**********************************************************
#
#**********************************************************
sub snmp_form_footer {
  my ($fields, $active_fields, $attr) = @_;

  my $table2 = $html->table({ width => '100%' });
  my @arr = ();
  foreach my $name (sort keys %$fields) {
    my $ex_info = ($attr->{OIDS_EXINFO}->{$name}{DESCRIBE}) ? " ($attr->{OIDS_EXINFO}->{$name}{ACCESS})" . $html->br() . "$attr->{OIDS_EXINFO}->{$name}{DESCRIBE}" : '';
    push @arr, $html->form_input('fields', "$name", { TYPE => 'checkbox', STATE => (in_array($name, $active_fields)) ? 1 : undef }) . ' ' . $html->b($name) . "$ex_info";

    if ($#arr > 2) {
      $table2->addrow(@arr);
      @arr = ();
    }
  }

  if ($#arr > -1) {
    $table2->addrow(@arr);
  }

  my $table = $html->table(
    {
      width       => '100%',
      title_plain => [ "$_REFRESH (sec): " . $html->form_input('REFRESH', int($FORM{REFRESH}), { SIZE => 4 }), $html->form_input('SHOW', $_SHOW, { TYPE => 'SUBMIT' }) ],
      cols_align => [ 'center:noprint', 'center:noprint' ],
    }
  );

  print $output .= $html->form_main(
    {
      CONTENT => $table2->show() . $table->show(),
      HIDDEN  => {
        index         => "$index",
        NAS_TYPE      => "$FORM{NAS_TYPE}",
        NAS_HOST      => "$FORM{NAS_HOST}",
        NAS_COMMUNITY => "$FORM{NAS_COMMUNITY}"
      },
      METHOD => 'GET'
    }
  );
}

#**********************************************************
#
#**********************************************************
sub snmputils_load_mibs {
  my ($mib_array, $attr) = @_;

  my %OIDS_EXINFO = ();

  #if (-d '../../Abills/MIBs/') {
  #  opendir DIR, '../../Abills/MIBs/' or die "Can't open dir '../../Abills/MIBs/' $!\n";
  #    my @contents = grep  !/^\.\.?$/  , readdir DIR;
  #  closedir DIR;
  #  foreach my $line (@contents) {
  #    $info{MIBS}.=$html->form_input('MIBS', "$line", { TYPE => 'checkbox', STATE => 0 }). " $line<br>\n";
  #   }
  #}
  #if ($FORM{MIBS}) {
  #   @mib_array = split(', ', $FORM{MIBS});
  #}

  my $message = '';
  foreach my $line (@$mib_array) {
    next if (!-f "../../Abills/MIBs/$line");
    my ($ret, $oid_hash, $oid_ex) = snmpMIB_to_OID_extended("../../Abills/MIBs/$line");
    $message .= "MIBS: $line Loaded\n" if ($debug == 1);

    while (my ($k, $v) = each %$oid_hash) {
      $OIDS_EXINFO{$k}{DESCRIBE} = $oid_ex->{$k}{DESCRIPTION} if ($oid_ex->{$k}{DESCRIPTION});
      $OIDS_EXINFO{$k}{ACCESS}   = $oid_ex->{$k}{ACCESS}      if ($oid_ex->{$k}{ACCESS});
      $OIDS_EXINFO{$k}{SYNTAX}   = $oid_ex->{$k}{SYNTAX}      if ($oid_ex->{$k}{SYNTAX});
      $OIDS_EXINFO{$k}{MIB}      = "$line"                    if (!$OIDS_EXINFO{$k}{MIB});
      snmpmapOID("$k", "$v");
    }
  }

  if ($debug > 0) {
    $html->pre($message);
  }

  return \%OIDS_EXINFO;
}

#**********************************************************
#
#**********************************************************
sub snmp_info_form {
  my %info = ();

  $info{ACTION}     = 'add';
  $info{ACTION_LNG} = $_ADD;
  snmpmapOID("ipRoutingTable", "1.3.6.1.2.1.4.21");

  # $SNMP_util::Debug = 1;
  my %OIDS_EXINFO = %{
    snmputils_load_mibs(
      [
        'SNMPv2-SMI',
        'SNMPv2-MIB',
        'SNMPv2-CONF',
        'SNMPv2-TC',
        'IF-MIB',
        'IP-MIB',
        'RFC1212-MIB',
        'RFC1155-SMI',
        'RFC1213-MIB',
        'ENTITY-MIB',

        #Cisco Mibs
        'CISCO-SMI',
        'CISCO-DOT11-IF-MIB',
        'CISCO-DOT11-ASSOCIATION-MIB',

        #'livingston.mib'
        'corporat.mib',
        'common.mib',
        'product.mib',

        #DOCSIS
        'DOCS-IF-MIB',
        'DOCS-CABLE-DEVICE-MIB',
        'DOCS-IF-EXT-MIB',

        #River Delta
        'RDN-MIB',

        'RDN-CABLE-SPECTRUM',
        'RDN-CABLE-SPECTRUM-GROUP-MIB',

        #                   'RDN-CMTS-MIB',
        'RDN-SYSLOG-MIB',

      ]
    )
  };

  $info{TYPE_SEL} = $html->form_select(
    'TYPE',
    {
      SELECTED => $FORM{TYPE} || 'dlink_ip_mac_port',
      SEL_HASH => {
        'system'            => 'RFC1213-MIB System information',
        'interfaces'        => 'IF-MIB:ifTable',
        'ipNetToMediaTable' => 'RFC1158-MIB:ipNetToMediaTable',
        'ipRoutingTable'    => 'RFC1158-MIB:ipRoutingTable',
        'tcpConnTable'      => 'RFC1213-MIB:tcpConnTable',
        'udpTable'          => 'RFC1213-MIB:udpTable',
        'zyxel_smf'         => 'Zyxel Static MAC Forwarding ',
        'dlink_ip_mac_port' => 'D-Link IP MAC Port Binding',
        'cisco_air'         => 'Cisco Aironet Asociation',
        'celan'             => 'CeLAN MAC Table',
        'cable_tester'      => 'Cable tester (D-Link)'
      },
      NO_ID => 1
    }
  );

  $info{NAS_SEL} = $html->form_select(
    'NAS_ID',
    {
      SELECTED          => $FORM{NAS_ID},
      SEL_MULTI_ARRAY   => [ [ '', '' ], @{ $Nas->list({ SORT => 1, PAGE_ROWS => 10000 }) } ],
      MULTI_ARRAY_KEY   => 0,
      MULTI_ARRAY_VALUE => 1,
    }
  );

  if ($FORM{change}) {
    my $SNMP_COMMUNITY = "$FORM{SNMP_COMMUNITY}\@$FORM{SNMP_HOST}";

    if ($FORM{NAS_ID}) {
      $Nas->info({ NAS_ID => $FORM{NAS_ID} });
      if (!$Nas->{NAS_MNG_PASSWORD}) {
        $html->message('err', $_ERROR, "NO SNMP COMMUNITY");
        return 0;
      }
      elsif (!$Nas->{NAS_MNG_IP_PORT}) {
        $html->message('err', $_ERROR, "NO SNMP HOST");
        return 0;
      }
      $SNMP_COMMUNITY = "$Nas->{NAS_MNG_PASSWORD}\@$Nas->{NAS_MNG_IP_PORT}";
    }

    my %REV_HASH      = reverse %OIDS_HASH;
    my $SNMP_OID_NAME = $REV_HASH{ $FORM{SNMP_OID} };
    print "-- $OIDS_EXINFO{$SNMP_OID_NAME}{SYNTAX} --";

    if ($FORM{set}) {

      my $SNMP_OID = $FORM{SNMP_OID};
      $SNMP_OID .= '.' . $FORM{SNMP_INDEX} if ($FORM{SNMP_INDEX});

      if (snmpset($SNMP_COMMUNITY, $FORM{SNMP_OID}, "$FORM{SNMP_TYPE}", "$FORM{SNMP_VALUE}")) {
        print $html->message('info', $_CHANGED, "$FORM{SNMP_OID} => $FORM{SNMP_VALUE}");
      }
    }

    if ($FORM{SNMP_INDEX}) {
      $FORM{SNMP_OID} = $FORM{SNMP_OID} . '.' . $FORM{SNMP_INDEX};
    }

    undef $FORM{SNMP_VALUES};
    $info{SNMP_VALUE} = snmpget($SNMP_COMMUNITY, $FORM{SNMP_OID});

    $info{SNMP_TYPE_SEL} = $html->form_select(
      'SNMP_TYPE',
      {
        SELECTED => $FORM{SNMP_TYPE},
        SEL_ARRAY =>
        [ 'int', 'integer', 'string', 'octetstring', 'octet string', 'oid', 'object id', 'object identifier', 'ipaddr', 'ip address', 'timeticks', 'uint', 'uinteger', 'uinteger32', 'unsigned int', 'unsigned integer', 'unsigned integer32', 'counter', 'counter32', 'counter64', 'gauge', 'gauge32' ],
        NO_ID => 1
      }
    );

    $html->tpl_show(_include('snmputils_set', 'Snmputils'), { %info, %FORM });
  }
  else {
    $info{DEBUG_SEL} = $html->form_select(
      'DEBUG',
      {
        SELECTED => $FORM{DEBUG} || 0,
        SEL_ARRAY => [ 0, 1, 2, 3, 4, 5 ],
        NO_ID     => 1
      }
    );

    $html->tpl_show(_include('snmputils_main', 'Snmputils'), { %info, %FORM });
  }

  if ($FORM{SHOW}) {
    my $rows_count = 0;
    $FORM{TYPE} = $FORM{SNMP_OID} if ($FORM{SNMP_OID});

    my $SNMP_COMMUNITY = "$FORM{SNMP_COMMUNITY}\@$FORM{SNMP_HOST}";

    if ($FORM{NAS_ID}) {
      $Nas->info({ NAS_ID => $FORM{NAS_ID} });
      if (!$Nas->{NAS_MNG_PASSWORD}) {
        $html->message('err', $_ERROR, "NO SNMP COMMUNITY");
        return 0;
      }
      elsif (!$Nas->{NAS_MNG_IP_PORT}) {
        $html->message('err', $_ERROR, "NO SNMP HOST");
        return 0;
      }

      $page_qs        = "&NAS_ID=$FORM{NAS_ID}";
      $SNMP_COMMUNITY = "$Nas->{NAS_MNG_PASSWORD}\@$Nas->{NAS_MNG_IP_PORT}";
    }
    else {
      $page_qs = "\&SNMP_COMMUNITY=$FORM{SNMP_COMMUNITY}\&SNMP_HOST=$FORM{SNMP_HOST}";
    }

    #External
    my $function = 'snmputils_' . $FORM{TYPE};
    if (defined(&$function)) {
      $function->({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
      return 0;
    }
    my %result  = &snmpwalkhash("$SNMP_COMMUNITY", \&my_simple_hash, $FORM{TYPE});
    my @CAPTION = keys %result;
    my @RES_ARR = sort { $a <=> $b } keys %{ $result{"$CAPTION[0]"} };

    if ($SNMP_Session::errmsg) {
      print $html->message('err', $_ERROR, "$FORM{TYPE}" . $html->br() . "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg");
    }

    if ($#RES_ARR > 0 && $FORM{TYPE} ne 'system') {
      $table = $html->table(
        {
          width      => '100%',
          caption    => "$_RESULT: $SNMP_COMMUNITY",
          border     => 1,
          title      => [ 'index', @CAPTION ],
          cols_align => [ 'left', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'center' ]
        }
      );

      foreach my $k (@RES_ARR) {
        my @arr = ($k);
        foreach my $ft (@CAPTION) {

          #$result{$ft}{$k} = data_convert($ft, $result{$ft}{$k});
          push @arr, ($OIDS_EXINFO{$ft}{ACCESS} eq 'read-write') ? $html->button("$result{$ft}{$k}", "index=$index&change=y&SNMP_INDEX=$k&SNMP_OID=$OIDS_HASH{$ft}$page_qs") : $result{$ft}{$k};
        }
        $table->addrow(@arr);
        $rows_count++;
      }
    }
    else {
      $table = $html->table(
        {
          width      => '100%',
          caption    => "$_RESULT: $SNMP_COMMUNITY",
          border     => 1,
          title      => [ 'MIB', 'OID Name', "inst", "$_VALUE", "ACCESS", "$_DESCRIBE" ],
          cols_align => [ 'left', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'right', 'center' ],
        }
      );

      foreach my $oid (keys %result) {
        foreach my $inst (sort { $a <=> $b } keys %{ $result{$oid} }) {
          $table->addrow(
            "$OIDS_EXINFO{$oid}{MIB}", "$oid", "$inst",
            $result{$oid}{$inst},
            ($OIDS_EXINFO{$oid}{ACCESS} eq 'read-write') ? $html->button($_CHANGE, "index=$index&change=y&SNMP_INDEX=$inst&SNMP_OID=$OIDS_HASH{$oid}$page_qs", { BUTTON => 1 }) : $OIDS_EXINFO{$oid}{ACCESS},
            $OIDS_EXINFO{$oid}{DESCRIBE}
          );
        }
        $rows_count++;
      }
    }

    print $table->show();

    $table = $html->table(
      {
        width      => '100%',
        cols_align => [ 'right', 'right' ],
        rowcolor   => $_COLORS[0],
        rows       => [ [ "$_TOTAL:", $html->b($rows_count) ] ]
      }
    );
    print $table->show();

    snmp_form_footer(\%result, \@CAPTION, { OIDS_EXINFO => \%OIDS_EXINFO });

    if ($FORM{TYPE} eq 'ipRoutingTable') {
      print $html->tpl_show(_include('snmputils_route', 'Snmputils'), \%info);
    }
  }
}

#**********************************************************
#
#**********************************************************
sub my_simple_hash {
  my ($h_ref, $host, $name, $oid, $inst, $value) = @_;
  $inst =~ s/^\.+//;

  my %ipNetToMediaType = (
    1 => 'other',
    2 => 'invalid',
    3 => 'dynamic',
    4 => 'static'
  );

  if ($name =~ /ifPhysAddress/ || $name =~ /ipNetToMediaPhysAddress/) {
    my $mac = '';
    map { $mac .= sprintf("%02X:", $_) } unpack "CCCCCC", $value;
    $value = $mac;
  }
  elsif ($name =~ /ipNetToMediaType/) {
    $value = $ipNetToMediaType{$value};
  }

  $h_ref->{$name}->{$inst} = $value;
}

#**********************************************************
# Read in the passed MIB file, parsing it
# for their text-to-OID mappings
#**********************************************************
sub snmpMIB_to_OID_extended ($) {
  my ($arg) = @_;
  my ($quote, $buf, $var, $code, $val, $tmp, $tmpv, $strt);
  my ($ret, $pass, $pos, $need2pass, $cnt, %prev);
  my (%Link) = (
    'org'          => 'iso',
    'dod'          => 'org',
    'internet'     => 'dod',
    'directory'    => 'internet',
    'mgmt'         => 'internet',
    'mib-2'        => 'mgmt',
    'experimental' => 'internet',
    'private'      => 'internet',
    'enterprises'  => 'private',
  );

  #my %OIDS_HASH = ();
  my %OIDS_EX = ();

  if (!open(MIB, $arg)) {
    carp "snmpMIB_to_OID: Can't open $arg: $!"
    unless ($SNMP_Session::suppress_warnings > 1);
    return -1;
  }
  print "snmpMIB_to_OID: loading $arg\n" if $SNMP_util::Debug;
  $ret       = 0;
  $pass      = 0;
  $need2pass = 1;
  $cnt       = 0;
  $pos       = tell(MIB);

  my %DESCRIBE_OIDS = ();

  #my @MIB_ARRAY =
  my $MIB_NAME;

  while ($need2pass) {
    while (<MIB>) {
      s/--.*--//g;    # throw away comments (-- anything --)
      s/--.*//;       # throw away comments (-- anything EOL)
      if ($quote) {
        next unless /\"/;
        $quote = 0;
      }
      chop;

      #
      #	$buf = "$buf $_";
      # Previous line removed (and following replacement)
      # suggested by Brian Reichert, reichert@numachi.com
      #
      $buf .= ' ' . $_;
      $buf =~ s/\s+/ /g;

      if ($buf =~ / DEFINITIONS ::= BEGIN/) {

        if ($buf =~ /(\S+) DEFINITIONS/) {
          $MIB_NAME = $1;

          #print "$MIB_NAME\n";
        }

        if ($pass == 0 && $need2pass) {
          seek(MIB, $pos, 0);
          $buf       = "";
          $pass      = 1;
          $need2pass = 0;
          $cnt       = 0;
          next;
        }
        $need2pass = 0;
        $pass      = 0;
        $pos       = tell(MIB);
        undef %Link;
        undef %prev;
        %Link = (
          'org'          => 'iso',
          'dod'          => 'org',
          'internet'     => 'dod',
          'directory'    => 'internet',
          'mgmt'         => 'internet',
          'mib-2'        => 'mgmt',
          'experimental' => 'internet',
          'private'      => 'internet',
          'enterprises'  => 'private',
        );
        $buf = "";
        next;
      }
      elsif ($buf =~ /FROM (\S+)/) {
        if (!$loaded_mibs{$1}) {
          print "FROM $1\n" if ($debug == 1);
        }
        $buf =~ s/FROM $1//;
      }
      if ($buf =~ /DESCRIPTION.+"(.+)"+/g) {
        $DESCRIBE_OIDS{DESCRIPTION} = $1;

        #next;
      }
      elsif ($buf =~ /ACCESS (\S+)/) {
        $DESCRIBE_OIDS{ACCESS} = $1;
        $buf =~ s/ACCESS $1//;
        next;
      }
      elsif ($buf =~ /(\S+) OBJECT-TYPE/) {
        $DESCRIBE_OIDS{'OBJECT-TYPE'} = $1;
      }
      elsif ($buf =~ /SYNTAX (\w+)/) {
        $DESCRIBE_OIDS{'SYNTAX'} = $1;
        $buf =~ s/ SYNTAX .*//;
        next;
      }

      $buf =~ s/OBJECT-TYPE/OBJECT IDENTIFIER/;
      $buf =~ s/OBJECT-IDENTITY/OBJECT IDENTIFIER/;
      $buf =~ s/OBJECT-GROUP/OBJECT IDENTIFIER/;
      $buf =~ s/MODULE-IDENTITY/OBJECT IDENTIFIER/;
      $buf =~ s/ IMPORTS .*\;//;
      $buf =~ s/ SEQUENCE {.*}//;

      $buf =~ s/ [\w-]+ ::= OBJECT IDENTIFIER//;
      $buf =~ s/ OBJECT IDENTIFIER .* ::= {/ OBJECT IDENTIFIER ::= {/;
      $buf =~ s/".*"//;

      if ($buf =~ /\"/) {
        $quote = 1;
      }

      if ($buf =~ / ([\w\-]+) OBJECT IDENTIFIER ::= {([^}]+)}/) {

        $var = $1;
        $buf = $2;
        undef $val;
        $buf =~ s/ +$//;
        ($code, $val) = split(' ', $buf, 2);

        $OIDS_EX{$var}{SYNTAX}      = $DESCRIBE_OIDS{SYNTAX};
        $OIDS_EX{$var}{ACCESS}      = $DESCRIBE_OIDS{ACCESS};
        $OIDS_EX{$var}{DESCRIPTION} = $DESCRIBE_OIDS{DESCRIPTION};
        %DESCRIBE_OIDS              = ();

        if (!defined($val) || (length($val) <= 0)) {

          #$SNMP_util::OIDS{$var} = $code;
          $OIDS_HASH{$var} = $code;
          $cnt++;
          print "'$var' => '$code'\n" if $SNMP_util::Debug;
        }
        else {
          $strt = $code;
          while ($val =~ / /) {
            ($tmp, $val) = split(' ', $val, 2);
            if ($tmp =~ /([\w\-]+)\((\d+)\)/) {
              $tmp = $1;
              if (exists($OIDS_HASH{$strt})) {
                $tmpv = "$OIDS_HASH{$strt}.$2";
              }
              else {
                $tmpv = $2;
              }
              $Link{$tmp} = $strt;
              if (!exists($prev{$tmp}) && exists($OIDS_HASH{$tmp})) {
                if ($tmpv ne $OIDS_HASH{$tmp}) {
                  $strt = "$strt.$tmp";
                  $OIDS_HASH{$strt} = $tmpv;
                  $cnt++;
                }
              }
              else {
                $prev{$tmp}      = 1;
                $OIDS_HASH{$tmp} = $tmpv;
                $cnt++;
                $strt = $tmp;
              }
            }
          }

          if (!exists($OIDS_HASH{$strt})) {
            if ($pass) {
              carp "snmpMIB_to_OID: $arg: \"$strt\" prefix unknown, load the parent MIB first.\n"
              unless ($SNMP_Session::suppress_warnings > 1);
              print "snmpMIB_to_OID: $arg: \"$strt\" prefix unknown, load the parent MIB first." . $html->br();
            }
            else {
              $need2pass = 1;
            }
          }
          $Link{$var} = $strt;
          if (exists($OIDS_HASH{$strt})) {
            $val = "$OIDS_HASH{$strt}.$val";
          }
          if (!exists($prev{$var}) && exists($OIDS_HASH{$var})) {
            if ($val ne $OIDS_HASH{$var}) {
              $var = "$strt.$var";
            }
          }

          $OIDS_HASH{$var} = $val;
          $prev{$var}      = 1;
          $cnt++;

          print "'$var' => '$val'\n" if $SNMP_util::Debug;
        }
        undef $buf;
      }
    }

    if ($pass == 0 && $need2pass) {
      seek(MIB, $pos, 0);
      $buf  = "";
      $pass = 1;
      $cnt  = 0;
    }
    else {
      $ret += $cnt;
      $need2pass = 0;
    }
  }
  close(MIB);
  $RevNeeded = 1;

  $loaded_mibs{$MIB_NAME} = 1;

  return ($ret, \%OIDS_HASH, \%OIDS_EX);
}

#**********************************************************
# binding ID binding
#**********************************************************
sub snmputils_binding {
  my $binding;

  $Snmputils->{ACTION}     = 'add';
  $Snmputils->{ACTION_LNG} = $_ADD;

  if ($FORM{add}) {
    $Snmputils->snmp_binding_add({%FORM});
    if (!$Snmputils->{errno}) {
      $html->message('info', $_INFO, "$_ADDED");
    }
  }
  elsif ($FORM{change}) {
    $Snmputils->snmp_binding_change({%FORM});
    if (!$Snmputils->{errno}) {
      $html->message('info', $_INFO, "$_CHANGED");
    }
  }
  elsif (defined($FORM{chg})) {
    $Snmputils->snmp_binding_info($FORM{chg}, {%FORM});
    if (!$Snmputils->{errno}) {
      $html->message('info', $_INFO, "$_CHANGING");
    }
    $Snmputils->{ACTION}     = 'change';
    $Snmputils->{ACTION_LNG} = $_CHANGE;
  }
  elsif (defined($FORM{del}) && defined($FORM{is_js_confirmed})) {
    $Snmputils->snmp_binding_del({ ID => $FORM{del} });
    if (!$Snmputils->{errno}) {
      $html->message('info', $_INFO, "$_DELETED");
    }
  }

  if ($Snmputils->{errno} == 7) {
    $html->message('err', $_ERROR, "$_EXIST '$FORM{BINDING}'");
  }
  elsif ($Snmputils->{errno}) {
    $html->message('err', $_ERROR, "[$Snmputils->{errno}] $err_strs{$Snmputils->{errno}}");
  }

  $html->tpl_show(_include('snmputils_binding', 'Snmputils'), { %$Snmputils, %FORM });
  $pages_qs = "&UID=$FORM{UID}";
  snmputils_binding_list();
}

#**********************************************************
# binding ID binding
#**********************************************************
sub snmputils_binding_list {

  my $list = $Snmputils->snmputils_binding_list({%LIST_PARAMS});

  $table = $html->table(
    {
      width      => '100%',
      caption    => "$_RESULT: $SNMP_COMMUNITY",
      border     => 1,
      title      => [ "$_USER", "ID", "$_PARAMS", "$_COMMENTS", '-', '-' ],
      cols_align => [ 'left', 'right', 'right', 'right', 'right', 'center', 'center' ],
      qs         => $pages_qs,
      pages      => $Snmputils->{TOTAL}
    }
  );

  foreach my $line (@$list) {
    my $delete = $html->button($_DEL, "index=$index&del=$line->[1]$pages_qs", { MESSAGE => "$_DEL [$line->[1]] ?", CLASS => 'del' });
    my $change = $html->button($_CHANGE, "index=$index&chg=$line->[4]$pages_qs", { CLASS => 'change' });

    $table->addrow($line->[0], $line->[1], $line->[2], $line->[3], $change, $delete);
  }

  print $table->show();
}

#**********************************************************
# binding users
#**********************************************************
sub snmputils_get_users {
  my ($attr) = @_;

  my %user_hash = ();
  my $list = $Snmputils->snmputils_binding_list({ IDS => $attr->{IDS}, PAGE_ROWS => 100000 });
  foreach my $line (@$list) {
    $user_hash{"$line->[1]"} = "$line->[0]:$line->[5]:$line->[6]:$line->[7]";
  }

  return \%user_hash;
}

#*******************************************************************
# http://www.celan.tw
#
#*******************************************************************
sub snmputils_celan_monitor {

}

#**********************************************************
#
#**********************************************************
sub snmputils_celan_version {
  my ($attr) = @_;

  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my %RESULT = ();
  $RESULT{version}        = '';
  $RESULT{SNMP_COMMUNITY} = $SNMP_COMMUNITY;

  if ($RESULT{version} = snmpget($SNMP_COMMUNITY, ".1.3.6.1.2.1.1.1.0")) {
    $RESULT{firmware} = snmpget($SNMP_COMMUNITY, ".1.3.6.1.4.1.655.5.15.1.1.2.0");
  }
  else {
    print "$SNMP_Session::suppress_warnings / $SNMP_Session::errmsg";
    return 0;
  }

  #Get ports state
  #my @result_ports = &snmpwalk("$SNMP_COMMUNITY", $RESULT{oid_prefix} . "$RESULT{oid_sufix}{STATE}" );
  #$RESULT{PORT_STATE}=\@result_ports;

  return \%RESULT;
}

#*******************************************************************
#
#*******************************************************************
sub snmputils_celan_list {
  my ($attr) = @_;

  my $debug          = $attr->{DEBUG}          || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  $SWITCH_INFO = '';

  #my $SWITCH_INFO = $attr->{SWITCH_INFO} || snmputils_zyxel_smf_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
  my %PREFIX = (
    1 => 'IP',
    2 => 'MAC',
    4 => 'PORT',
    5 => 'ACTIVE',
    6 => 'MODE'
  );

  my %active  = ();
  my %dynamic = ();

  #Full list
  my @result = &snmpwalk("$SNMP_COMMUNITY", '.1.3.6.1.4.1.655.5.15.1.4.2.8.1.2');
  print '.1.3.6.1.4.1.655.5.15.1.4.2.8.1.2<BR>' if ($debug > 0);

  foreach my $line (@result) {
    print "$line" . $html->br() if ($debug > 0);

    # Get port
    my ($number, $mac_port) = split(/:/, $line);
    my @out_arr = unpack("H2H2H2H2H2H2H2H2H2H2", $mac_port);
    my $mac = uc(join(':', @out_arr[ 0 .. 5 ]));
    next if ($mac eq '00:00:00:00:00:00');
    my $port = join('', @out_arr[ 6 .. 9 ]);
    if ($debug > 0) {
      print "$number, $mac -> $port / $out /" . $html->br();
    }

    $active{MAC}{ $number . '-' . $mac } = $mac;
    $string = join('.', unpack("B32", pack('H*', $port))) . $html->br();
    if ($string =~ m/1/g) {
      $active{PORT}{ $number . '-' . $mac } = 32 - pos($string) + 1;
    }
  }

  return \%active, \%dynamic if ($attr->{ACTIVE_ONLY});

  @result = &snmpwalk("$SNMP_COMMUNITY", '.1.3.6.1.4.1.655.5.15.1.4.4.1.2');
  print '.1.3.6.1.4.1.655.5.15.1.4.4.1.2<BR>' if ($debug > 0);

  foreach my $line (@result) {
    print "$line" . $html->br() . "\n" if ($debug > 0);

    # Get port
    my ($number, $mac_port) = split(/:/, $line);
    my @out_arr = unpack("H2H2H2H2H2H2H2H2H2H2", $mac_port);
    my $mac  = join(':', @out_arr[ 0 .. 5 ]);
    my $port = join('',  @out_arr[ 6 .. 9 ]);
    if ($debug > 0) {
      print "$number, $mac -> $port / $out /" . $html->br();
    }

    $dynamic{MAC}{ $number . '-' . $mac } = $mac;
    $string = join('.', unpack("B32", pack('H*', $port))) . $html->br();
    if ($string =~ m/1/g) {
      $dynamic{PORT}{ $number . '-' . $mac } = 32 - pos($string) + 1;
    }
  }

  return \%active, \%dynamic;
}

#*******************************************************************
#
#  port on
# snmpset -c uhfdbwfgf -v 2c 10.12.222.5 .1.3.6.1.4.1.655.5.15.1.2.1.1.5.1 i 1
#
# port off
# snmpset -c uhfdbwfgf -v 2c 10.12.222.5 .1.3.6.1.4.1.655.5.15.1.2.1.1.5.1 i 2
#  17:03:53:           )
#port name
#snmpset -c uhfdbwfgf -v 2c 10.12.222.5 .1.3.6.1.4.1.655.5.15.1.2.1.1.2.1 s hawk
#
#*******************************************************************
sub snmputils_celan_add {
  my ($attr) = @_;

  my $message = '';
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';

  #my $sw_info = $attr->{SWITCH_INFO} || snmputils_zyxel_smf_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });

  my $ip        = $attr->{IP}      || '0.0.0.0';
  my $port_list = $attr->{PORT_ID} || 1;
  my $mac       = $attr->{MAC}     || 0;
  my $vlan      = $attr->{VLAN}    || 1;
  my $active    = $attr->{STATE}   || 0;
  my $debug     = $attr->{DEBUG}   || 0;

  my $oid = '.1.3.6.1.4.1.655.5.15.1.4.2.8.1.2.' . $vlan;
  $mac =~ s/-|://g;

  my $position  = 32 - $port_list;
  my $ports_bin = '00000000000000000000000000000000';
  substr($ports_bin, $position, 1, '1');

  my $str = join('.', unpack("B48", pack('H*', $mac))) . $ports_bin;

  print "$oid => $str\n" if ($debug > 3);
  if (snmpset($SNMP_COMMUNITY, $oid, "string", pack("B80", $str))) {

    #Ports on
    snmpset($SNMP_COMMUNITY, ".1.3.6.1.4.1.655.5.15.1.2.1.1.5.$port_list", "integer", 1);
    if ($attr->{LOGIN}) {
      snmpset($SNMP_COMMUNITY, ".1.3.6.1.4.1.655.5.15.1.2.1.1.2.1.$port_list", "string", "$attr->{LOGIN}");
    }
    $message .= "Added MAC: '$mac'\n";
  }

  return $message;
}

#*******************************************************************
# http://zyxel.ru/content/support/knowledgebase/KB-1466
#
#*******************************************************************
sub snmputils_celan_state {
  my ($attr) = @_;

  my $ip             = $attr->{IP}             || '0.0.0.0';
  my $mac            = $attr->{MAC}            || 0;
  my $vlan           = $attr->{VLAN}           || 0;
  my $state          = $attr->{STATE}          || 0;
  my $debug          = $attr->{DEBUG}          || 0;
  my $port_list      = $attr->{PORT_ID}        || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $oid            = '.1.3.6.1.4.1.655.5.15.1.4.2.8.1.2.' . $vlan;
  my $message        = '';

  $mac = '000000000000';
  my $position  = 32 - $port_list;
  my $ports_bin = '00000000000000000000000000000000';
  substr($ports_bin, $position, 1, '1');

  my $str = join('.', unpack("B48", pack('H*', $mac))) . $ports_bin;

  print "$oid => $str\n" if ($debug > 2);
  if (snmpset($SNMP_COMMUNITY, $oid, "string", pack("B80", $str))) {

    # Port Off
    snmpset($SNMP_COMMUNITY, ".1.3.6.1.4.1.655.5.15.1.2.1.1.5.$port_list", "integer", 2);
    $message .= " Deleted $_PORT: '$port_list'\n";
  }

  return $message;
}

#*******************************************************************
#
#*******************************************************************
sub snmputils_celan {
  my ($attr) = @_;

  my $debug          = $FORM{DEBUG}            || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $message        = '';

  if ($FORM{TEST}) {
    $html->pre(snmputils_celan({ DEBUG => $FORM{DEBUG} }));
    return 0;
  }
  elsif ($FORM{UPDATE}) {
    my $info = snmputils_celan(
      {
        NAS_IDS => $FORM{NAS_ID},
        DEBUG   => 1
      }
    );
    $html->pre($info);
  }

  my $SWITCH_INFO = snmputils_celan_version({ SNMP_COMMUNITY => $SNMP_COMMUNITY });
  $table = $html->table(
    {
      width      => '400',
      cols_align => [ 'left', 'right' ],
      rows       => [ [ "VERSION:", $html->b($SWITCH_INFO->{version}) ], [ "FIRMWARE", $SWITCH_INFO->{firmware} ] ]
    }
  );
  print $table->show();
  $Snmputils->{ACTION}     = 'add';
  $Snmputils->{ACTION_LNG} = $_ADD;

  if ($FORM{add}) {
    my $message = snmputils_celan_add(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        IP             => $FORM{IP},
        PORT_ID        => $FORM{PORT},
        MAC            => "$FORM{MAC_1}-$FORM{MAC_2}-$FORM{MAC_3}-$FORM{MAC_4}-$FORM{MAC_5}-$FORM{MAC_6}",
        SWITCH_INFO    => $SWITCH_INFO,
        VLAN           => $FORM{VLAN},
        STATE          => $FORM{ACTIVE},
        DEBUG          => $FORM{DEBUG},
        LOGIN          => $FORM{NAME},
      }
    );
    print $html->message('info', $_INFO, "$message");
  }
  elsif ($FORM{state}) {
    my $message = snmputils_celan_state(
      {
        SNMP_COMMUNITY => $SNMP_COMMUNITY,
        STATE          => $FORM{state},
        PORT_ID        => $FORM{PORT},
        SWITCH_INFO    => $SWITCH_INFO,
        VLAN           => $FORM{VLAN},
        MAC            => $FORM{MAC},
        DEBUG          => $FORM{DEBUG}
      }
    );

    print $html->message('info', $_INFO, "$message");
  }
  elsif ($FORM{MAIN_CONF}) {
    if (snmpset($SNMP_COMMUNITY, "$MAIN_OPTIONS{$FORM{MAIN_CONF}}", "integer", "$FORM{key}")) {
      $message .= "Ok\n";
    }

    print $html->message('info', $_INFO, "$FORM{MAIN_CONF} $MAIN_OPTIONS{$FORM{MAIN_CONF}} $message");
  }
  elsif ($FORM{RESET}) {
    if (snmpset($SNMP_COMMUNITY, "$MAIN_OPTIONS{$FORM{MAIN_CONF}}", "integer", "$FORM{key}")) {
      $message .= "Ok\n";
    }
    print $html->message('info', $_INFO, "Reseted");
  }

  #Port section
  $table = $html->table(
    {
      width      => '100%',
      caption    => "CeLAN Static MAC",
      border     => 1,
      title      => [ "$_USER", "$_PORT", "$_STATE", "$_NUM", "MAC", "$_NAME", "-" ],
      cols_align => [ 'left', 'left', 'center', 'right', 'right', 'right', 'right', 'center', 'center', 'center' ],
    }
  );

  my @ports = ();
  my %MODES = (0 => 'ARP', 1 => 'ACL');

  my ($ACTIVE_MAC, $DYNAMIC_MAC) = snmputils_celan_list(
    {
      SNMP_COMMUNITY => $SNMP_COMMUNITY,
      SWITCH_INFO    => $SWITCH_INFO,
      DEBUG          => $FORM{DEBUG},
      ACTIVE_ONLY    => 1
    }
  );

  #my multiports  section
  my $binding;
  if ($FORM{GET_USERS}) {
    my $IDS = '';
    while (my ($ip, $mac) = each %{ $ACTIVE_MAC->{MAC} }) {
      $IDS .= "'$mac',";
    }

    chop($IDS);
    $binding = snmputils_get_users({ IDS => "$IDS" });
  }

  my %STATUS = (
    1 => $_DISABLE,
    3 => $_ENABLE
  );

  my $page_arguments = '';
  while (my ($vlan_mac, $mac) = each %{ $ACTIVE_MAC->{MAC} }) {
    my ($VLAN, $m) = split(/-/, $vlan_mac, 2);
    my $state = $ACTIVE_MAC->{ACTIVE}{$vlan_mac};

    next if ($m eq '00:00:00:00:00:00');

    if ($FORM{NAS_ID}) {
      $page_arguments = "&NAS_ID=$FORM{NAS_ID}";
    }
    else {
      $page_arguments = "&SNMP_HOST=$FORM{SNMP_HOST}&SNMP_COMMUNITY=$FORM{SNMP_COMMUNITY}";
    }

    my @arr = (
      $table->td($ACTIVE_MAC->{PORT}{$vlan_mac}),
      $table->td($STATUS{$state}, { bgcolor => ($state == 3) ? '#00FF00' : $_COLORS[1] }),
      $table->td($VLAN),
      $table->td($m),
      $table->td($ACTIVE_MAC->{NAME}{$vlan_mac}),

      #$table->td($html->button(($state == 3) ? $STATUS{1} : $STATUS{3},
      #  "$page_arguments&TYPE=$FORM{TYPE}&SHOW=1&index=$index&VLAN=$VLAN&MAC=$ACTIVE_MAC->{MAC}{$vlan_mac}&PORT=$ACTIVE_MAC->{PORT}{$vlan_mac}&state=". (($state == 3) ? 1 : 3) )),
      $table->td($html->button($_DEL, "index=$index&VLAN=$VLAN&MAC=$ACTIVE_MAC->{MAC}{$vlan_mac}$page_arguments&TYPE=$FORM{TYPE}&SHOW=1&state=2&PORT=$ACTIVE_MAC->{PORT}{$vlan_mac}", { CLASS => 'del' }))
    );

    if ($binding->{ $ACTIVE_MAC->{MAC}{$vlan_mac} }) {
      my ($name, $uid) = split(/:/, $binding->{ $ACTIVE_MAC->{MAC}{$vlan_mac} });
      unshift @arr, $table->td($html->button("$name", "index=15&UID=$uid"));
    }
    else {
      unshift @arr, $table->td('-');
    }

    $table->addtd(@arr);
  }

  print $table->show();

  return 0 if (!$FORM{DYNAMIC_MACS});

  $table = $html->table(
    {
      width      => '100%',
      caption    => "CeLAN Static MAC",
      border     => 1,
      title      => [ "$_USER", "$_PORT", "$_STATE", "$_NUM", "MAC", "$_NAME", "-" ],
      cols_align => [ 'left', 'left', 'center', 'right', 'right', 'right', 'right', 'center', 'center', 'center' ],
    }
  );

  $Snmputils->{ACTIVE} = 'checked';
  $html->tpl_show(_include('snmputils_mac_port_add', 'Snmputils'), { %$Snmputils, %FORM });

  while (my ($vlan_mac, $mac) = each %{ $DYNAMIC_MAC->{MAC} }) {
    my ($VLAN, $mac) = split(/-/, $vlan_mac, 2);
    my $state = $DYNAMIC_MAC->{ACTIVE}{$vlan_mac};

    next if ($mac eq '00:00:00:00:00:00');
    if ($FORM{NAS_ID}) {
      $page_arguments = "&NAS_ID=$FORM{NAS_ID}";
    }
    else {
      $page_arguments = "&SNMP_HOST=$FORM{SNMP_HOST}&SNMP_COMMUNITY=$FORM{SNMP_COMMUNITY}";
    }

    my @arr = (
      $table->td($DYNAMIC_MAC->{PORT}{$vlan_mac}),
      $table->td($STATUS{$state}, { bgcolor => ($state == 3) ? '#00FF00' : $_COLORS[1] }),
      $table->td($VLAN),
      $table->td($mac),
      $table->td($DYNAMIC_MAC->{NAME}{$vlan_mac}),

      #$table->td($html->button(($state == 3) ? $STATUS{1} : $STATUS{3},
      #  "$page_arguments&TYPE=$FORM{TYPE}&SHOW=1&index=$index&VLAN=$VLAN&MAC=$ACTIVE_MAC->{MAC}{$vlan_mac}&PORT=$ACTIVE_MAC->{PORT}{$vlan_mac}&state=". (($state == 3) ? 1 : 3) )),
      #$table->td($html->button($_ADD, "index=$index&VLAN=$VLAN&MAC=$DYNAMIC_MAC->{MAC}{$vlan_mac}$page_arguments&TYPE=$FORM{TYPE}&SHOW=1&state=2&PORT=$ACTIVE_MAC->{PORT}{$vlan_mac}", { BUTTON => 1 }))
    );

    if ($binding->{ $DYNAMIC_MAC->{MAC}{$vlan_mac} }) {
      my ($name, $uid) = split(/:/, $binding->{ $DYNAMIC_MAC->{MAC}{$vlan_mac} });
      unshift @arr, $table->td($html->button("$name", "index=15&UID=$uid"));
    }
    else {
      unshift @arr, $table->td('-');
    }

    $table->addtd(@arr);
  }

  print $table->show();
}

#**********************************************************
# HOST,
# COMMUNITY:
# IP/MAC
#
#
#**********************************************************
sub snmputils_celan_macs {
  my ($attr) = @_;

  my $debug          = $attr->{DEBUG} || 0;
  my $NAS_ID         = $attr->{NAS_ID};              #
  my $MNG_PASSWORD   = $attr->{MNG_PASSWORD};        #
  my $MNG_HOST       = $attr->{MNG_HOST};            #
  my $RAD_PAIRS      = $attr->{RAD_PAIRS};           #
  my $SNMP_COMMUNITY = "$MNG_PASSWORD\@$MNG_HOST";

  my $debug_output = '';
  my ($ACTIVE_MAC, $BLOCK_MAC) = snmputils_celan_list(
    {
      SNMP_COMMUNITY => $SNMP_COMMUNITY,
      SWITCH_INFO    => $SWITCH_INFO,
      ACTIVE_ONLY    => 1,
    }
  );

  my %SERVER_MAC    = ();                            #Now active in server
  my %MUST_ACTIVATE = ();                            #Need to be active
  if ($ACTIVE_MAC->{MAC}) {

    # IP -> MAC
    %SERVER_MAC = %{ $ACTIVE_MAC->{MAC} };
  }

  my $list = $Snmputils->snmputils_nas_ipmac(
    {
      NAS_ID    => $NAS_ID,
      PG        => 0,
      PAGE_ROWS => 100000,
      DISABLE   => 0
    }
  );

  foreach my $line (@$list) {
    my $user_ports = 0;
    my $login      = $line->[9];
    if ($line->[7]) {
      $user_ports = $line->[7];
    }

    $debug_output .= "Allow NAS: $line->[0] DHCP NAS: $line->[8] UID: $line->[1] IP: $line->[2] MAC: $line->[3] VID: $line->[6] PORT: $line->[7]\n" if ($debug > 2);
    if ($line->[4] >= $conf{SNMPUTILS_BINDING_DEPOSIT} && ($line->[8] == 0 || $line->[8] == $NAS_ID)) {
      if ($line->[7]) {
        $MUST_ACTIVATE{ "$line->[6]-" . uc($line->[3]) } = "$line->[7]";
      }
    }
    else {
      $debug_output .= " Negative deposit\n" if ($debug > 2);
    }
  }

  while (my ($vid_mac, $mac) = each %SERVER_MAC) {
    my ($vid, $m) = split(/-/, $vid_mac, 2);
    next if ($mac eq '00:00:00:00:00:00');
    $debug_output .= "Server NUMBER: '$vid' MAC: $mac" if ($debug > 0);
    if ($MUST_ACTIVATE{ '0-' . $mac }) {
      delete $MUST_ACTIVATE{ '0-' . $mac };
      delete $SERVER_MAC{ '0-' . $mac };
      $debug_output .= " Skip...\n" if ($debug > 0);
    }
    else {
      if ($debug < 3) {
        my $message = snmputils_celan_state(
          {
            SNMP_COMMUNITY => $SNMP_COMMUNITY,
            STATE          => 2,
            PORT_ID        => $ACTIVE_MAC->{PORT}{ $vid . '-' . $mac },
            SWITCH_INFO    => $SWITCH_INFO,
            VLAN           => $vid,
            MAC            => $mac,
            DEBUG          => $debug
          }
        );
      }
      $debug_output .= " Delete\n" if ($debug > 0);
    }
  }

  #Must active
  $debug_output .= "Add to server:\n" if ($debug > 0);
  while (my ($vid_mac, $port) = each %MUST_ACTIVATE) {
    $debug_output .= "$vid_mac Port: $port\n" if ($debug > 0);
    my ($vid, $mac) = split(/-/, $vid_mac, 2);

    #Don't add mac to 0 port
    if ($port == 0) {
      $debug_output .= "Error: Port: $port Skip\n" if ($debug > 0);
      next;
    }

    if ($debug < 3) {
      my $message = snmputils_celan_add(
        {
          SNMP_COMMUNITY => $SNMP_COMMUNITY,
          PORT_ID        => $port,
          MAC            => "$mac",
          SWITCH_INFO    => $SWITCH_INFO,
          VLAN           => $vid,
          STATE          => 3,
          DEBUG          => $debug,
          LOGIN          =>,
        }
      );

      $debug_output .= "! $message\n";
    }
  }

  $DEBUG = $debug_output;
  return $debug_output;
}

#**********************************************************
#
#**********************************************************
sub snmputils_cable_tester {
  my ($attr) = @_;

  my $debug          = $FORM{DEBUG}            || 0;
  my $SNMP_COMMUNITY = $attr->{SNMP_COMMUNITY} || '';
  my $message        = '';

  if ($FORM{TEST}) {
    if ($FORM{TEST} =~ /(\d+)\-(\d+)/) {
      my $start = $1;
      my $stop  = $2;
      for ($i = $start ; $i <= $stop ; $i++) {
        &snmpset("$SNMP_COMMUNITY", "1.3.6.1.4.1.171.12.58.1.1.1.12.$FORM{TEST}", 'integer', int($FORM{TEST}));
      }
    }
    elsif (&snmpset("$SNMP_COMMUNITY", "1.3.6.1.4.1.171.12.58.1.1.1.12.$FORM{TEST}", 'integer', int($FORM{TEST}))) {
      $html->message('info', $_INFO, "$_PORT: $FORM{TEST} $_TEST Started");
    }
    else {
      $html->message('err', $_ERROR, "$_PORT: $FORM{TEST} $_TEST Started / $SNMP_Session::suppress_warnings / $SNMP_Session::errmsg");
    }
  }

  my %links_states_hash = ();
  my %pairs_status      = ();
  my %pairs_length      = ();
  my %test_status       = ();

  my @result_ports = &snmpwalk("$SNMP_COMMUNITY", "1.3.6.1.4.1.171.12.58.1.1.1.2");

  if ($#result_ports > -1) {

    #Links states
    my @links_states = &snmpwalk("$SNMP_COMMUNITY", "1.3.6.1.4.1.171.12.58.1.1.1.3 ");
    foreach my $line (@links_states) {
      if ($line =~ /(\d+):(\d+)/) {
        $links_states_hash{$1} = $2;
      }
    }

    my @result = &snmpwalk("$SNMP_COMMUNITY", "1.3.6.1.4.1.171.12.58.1.1.1.12");
    foreach my $line (@result) {
      if ($line =~ /(\d+):(\d+)/) {
        $test_status{$1} = $2;
      }
    }

    #Pair Status
    # 1.3.6.1.4.1.171.12.58.1.1.1.4 - c  
    # 1.3.6.1.4.1.171.12.58.1.1.1.5 - c  
    # 1.3.6.1.4.1.171.12.58.1.1.1.6 - c  
    # 1.3.6.1.4.1.171.12.58.1.1.1.7 - c  

    my $pair = 1;
    foreach my $oid (('1.3.6.1.4.1.171.12.58.1.1.1.4', '1.3.6.1.4.1.171.12.58.1.1.1.5', '1.3.6.1.4.1.171.12.58.1.1.1.6', '1.3.6.1.4.1.171.12.58.1.1.1.7')) {
      my @states = &snmpwalk("$SNMP_COMMUNITY", "$oid");
      foreach my $line (@states) {
        if ($line =~ /(\d+):(\d+)/) {
          $pairs_status{$pair}{$1} = $2;
        }
      }
      $pair++;
    }

    #Pairs length
    $pair = 1;
    foreach my $oid (('1.3.6.1.4.1.171.12.58.1.1.1.8', '1.3.6.1.4.1.171.12.58.1.1.1.9', '1.3.6.1.4.1.171.12.58.1.1.1.10', '1.3.6.1.4.1.171.12.58.1.1.1.11')) {
      my @states = &snmpwalk("$SNMP_COMMUNITY", "$oid");
      foreach my $line (@states) {
        if ($line =~ /(\d+):(\d+)/) {
          $pairs_length{$pair}{$1} = $2;
        }
      }
      $pair++;
    }
  }
  else {
    $html->message('info', $_INFO, "$_NOT_SUPPORT");
  }

  my $table = $html->table(
    {
      caption => "Cable tester",
      width   => '100%',
      title   => [ "$_PORTS", "$_TYPE", "$_STATE", "Pairs STATUS", "$_LENGTH", "$_TEST $_STATUS" ],
      cols_align => [ 'left', 'right', ],
      ID         => 'SNMPUTILS_CABLE_TESTER'
    }
  );

  my @link_types  = ('fastEthernet(0)', 'gigaEthernet(1)', 'other(2)');
  my @link_status = ('link-down(0)',    'link-up(1)',      'other(2)');
  my @pair_status = ('ok(0)',           'open(1)',         'short(2)', 'open-short(3)', 'crosstalk(4)', 'unknown(5)', 'count(6)', 'no-cable(7)', 'other(8)');
  my @test_status = ('action(1)',       'processing(2)',   'other(3)');

  foreach my $line (@result_ports) {
    print "$line" if ($debug > 2);
    if ($line =~ /(\d+):(\d+)/) {
      my $port = $1;
      my $type = $2;
      $table->addrow(
        $port,
        $link_types[$type],
        $link_status[ $links_states_hash{$port} ],
        "$pair_status[$pairs_status{1}{$port}]" . $html->br() . "$pair_status[$pairs_status{2}{$port}]" . $html->br() . "$pair_status[$pairs_status{3}{$port}]" . $html->br() . "$pair_status[$pairs_status{4}{$port}]",
        "$pairs_length{1}{$port}" . $html->br() . "$pairs_length{2}{$port}" . $html->br() . "$pairs_length{3}{$port}" . $html->br() . "$pairs_length{4}{$port}",
        ($test_status{$port} != 3) ? $test_status[ $test_status{$port} ] : $html->button("$_TEST", "index=$index&NAS_ID=$FORM{NAS_ID}&TYPE=$FORM{TYPE}&SHOW=1&TEST=$port", { BUTTON => 1 })
      );
    }
  }

  print $table->show();

  print $html->form_main(
    {
      CONTENT => '',
      HIDDEN  => {
        index  => "$index",
        NAS_ID => $FORM{NAS_ID},
        TYPE   => $FORM{TYPE},
        SHOW   => 1,
        TEST   => '1-' . ($#result_ports + 1)
      },
      SUBMIT => { TEST_ALL => "$_TEST $_ALL" },
      METHOD => 'GET'
    }
  );

}
1

