package pf::SNMP::Nortel::BayStack5500_6_1;

=head1 NAME

pf::SNMP::Nortel::BayStack5500_6_1 - Object oriented module to access SNMP enabled Nortel BayStack5500 switches running software code >= 6.0.x

=head1 SYNOPSIS

The pf::SNMP::Nortel::BayStack5500_6_1 module implements an object 
oriented interface to access SNMP enabled Nortel::BayStack5500_6_1 switches.

=cut

use strict;
use warnings;
use diagnostics;
use Log::Log4perl;
use Net::SNMP;
use base ('pf::SNMP::Nortel');


#### sub getBoardPortFromIfIndex 
sub getBoardPortFromIfIndex {
    my ( $this, $ifIndex ) = @_;
    my $boardIndx = int($ifIndex / 128);
    my $portIndx  = $ifIndex - ($boardIndx * 128);
    $boardIndx++;
    return ( $boardIndx, $portIndx );
}


#### sub getIfIndexFromBoardPort
sub getIfIndexFromBoardPort {
    my ( $this, $board, $port ) = @_;
    my $ifIndex  = $board==0 ? $board*128+$port : ($board-1)*128+$port;
    return ( $ifIndex );
}


#### sub parseTrap
sub parseTrap {
    my ( $this, $trapString ) = @_;
    my $trapHashRef;
    my $logger = Log::Log4perl::get_logger( ref($this) );
    if ( $trapString
        =~ /^BEGIN TYPE ([23]) END TYPE BEGIN SUBTYPE 0 END SUBTYPE BEGIN VARIABLEBINDINGS \.1\.3\.6\.1\.2\.1\.2\.2\.1\.1\.(\d+) = INTEGER: \d+\|\.1\.3\.6\.1\.2\.1\.2\.2\.1\.7\.\d+ = INTEGER: [^|]+\|\.1\.3\.6\.1\.2\.1\.2\.2\.1\.8\.\d+ = INTEGER: [^)]+\)/
        )
    {
        $trapHashRef->{'trapType'} = ( ( $1 == 2 ) ? "down" : "up" );
        $trapHashRef->{'trapIfIndex'} = $2;
    } elsif ( $trapString
        =~ /\|\.1\.3\.6\.1\.4\.1\.45\.1\.6\.5\.3\.12\.1\.3\.(\d+)\.(\d+) = Hex-STRING: ([0-9A-F]{2} [0-9A-F]{2} [0-9A-F]{2} [0-9A-F]{2} [0-9A-F]{2} [0-9A-F]{2})/
        )
    {

        $trapHashRef->{'trapType'}    = 'secureMacAddrViolation';
        $trapHashRef->{'trapIfIndex'} = ( $1 - 1 ) * 128 + $2;
        $trapHashRef->{'trapMac'}     = lc($3);
        $trapHashRef->{'trapMac'} =~ s/ /:/g;
        $trapHashRef->{'trapVlan'} = $this->getVlan( $trapHashRef->{'trapIfIndex'} );
        $logger->debug( "ifIndex for " . $trapHashRef->{'trapMac'} . " on switch " . $this->{_ip} . " is " . $trapHashRef->{'trapIfIndex'} );
        #}
    } else {
        $logger->debug("trap currently not handled");
        $trapHashRef->{'trapType'} = 'unknown';
    }
    return $trapHashRef;
}


#### sub getSecureMacAddresses
sub getSecureMacAddresses {
        my ( $this, $ifIndex ) = @_;
        my $logger = Log::Log4perl::get_logger( ref($this) );
        my $OID_s5SbsAuthCfgAccessCtrlType = '1.3.6.1.4.1.45.1.6.5.3.10.1.4'; #S5-SWITCH-BAYSECURE-MIB
        my $secureMacAddrHashRef = {};

        if ( !$this->connectRead() ) {
                return $secureMacAddrHashRef;
        }
        my ( $boardIndx, $portIndx ) = $this->getBoardPortFromIfIndex($ifIndex);
        my $oldVlan = $this->getVlan($ifIndex);

        # check for boardIndx == 0
        my $OID_s5SbsAuthCfgBrdIndx = '.1.3.6.1.4.1.45.1.6.5.3.10.1.1';
        my $result = $this->{_sessionRead}->get_next_request(
                        -varbindlist => [$OID_s5SbsAuthCfgBrdIndx]
                );
        # if get_next_request() result = 0 (i.e. 1st boardIndx=0) then subtract 1 from the boardIndx that was
        # returned above by the sub getBoardPortFromIfIndex($ifIndex)
        foreach my $key ( keys %{$result} ) {
                if($result->{$key}==0){
                        $boardIndx--;
                }
        }

        $logger->trace("SNMP get_table for s5SbsAuthCfgAccessCtrlType: $OID_s5SbsAuthCfgAccessCtrlType.$boardIndx.$portIndx");
        $result = $this->{_sessionRead}->get_table(
                -baseoid => "$OID_s5SbsAuthCfgAccessCtrlType.$boardIndx.$portIndx"
        );
        while ( my ( $oid_including_mac, $ctrlType ) = each( %{$result} ) ) {
                if ((   $oid_including_mac
                        =~ /^$OID_s5SbsAuthCfgAccessCtrlType\.$boardIndx\.$portIndx\.([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/)
                        && ( $ctrlType == 1 )){
                        my $oldMac = sprintf( "%02x:%02x:%02x:%02x:%02x:%02x", $1, $2, $3, $4, $5, $6 );
                        push @{ $secureMacAddrHashRef->{$oldMac} }, $oldVlan;
                }
        }
        return $secureMacAddrHashRef;
}


#called with $authorized set to true, creates a new line to authorize the MAC
#when $authorized is set to false, deletes an existing line
sub _authorizeMAC {
    my ( $this, $ifIndex, $MACHexString, $authorize ) = @_;
    my $OID_s5SbsAuthCfgAccessCtrlType = '1.3.6.1.4.1.45.1.6.5.3.10.1.4';
    my $OID_s5SbsAuthCfgStatus         = '1.3.6.1.4.1.45.1.6.5.3.10.1.5';
    my $logger = Log::Log4perl::get_logger( ref($this) );

    if ( !$this->isProductionMode() ) {
	$logger->info("not in production mode ... we won't delete an entry from the SecureMacAddrTable");
      	return 1;
    }

    my ( $boardIndx, $portIndx ) = $this->getBoardPortFromIfIndex($ifIndex);

    my $cfgStatus = ($authorize) ? 2 : 3;

    #convert MAC into decimal
    my @MACArray = split( /:/, $MACHexString );
    my $MACDecString = '';
    foreach my $hexPiece (@MACArray) {
        if ( $MACDecString ne '' ) {
            $MACDecString .= ".";
        }
        $MACDecString .= hex($hexPiece);
    }

    if ( !$this->connectWrite() ) {
         return 0;
    }
    my $result;

    if ($authorize) {
        $logger->trace("SNMP set_request for s5SbsAuthCfgAccessCtrlType: $OID_s5SbsAuthCfgAccessCtrlType");
        $result = $this->{_sessionWrite}->set_request(
            -varbindlist => [
                "$OID_s5SbsAuthCfgAccessCtrlType.$boardIndx.$portIndx.$MACDecString",
                Net::SNMP::INTEGER,
                1,
                "$OID_s5SbsAuthCfgStatus.$boardIndx.$portIndx.$MACDecString",
                Net::SNMP::INTEGER,
                $cfgStatus
            ]
        );

    } else {
	$logger->trace("SNMP set_request for s5SbsAuthCfgStatus: $OID_s5SbsAuthCfgStatus");
        $result = $this->{_sessionWrite}->set_request(
            -varbindlist => [
                "$OID_s5SbsAuthCfgStatus.$boardIndx.$portIndx.$MACDecString",
                Net::SNMP::INTEGER,
                $cfgStatus
            ]
        );
    }
    return ( defined($result) );
}
