#!/usr/bin/perl
#
# SNMP query script to generate the requisite output for the 
# smartBridges airPoint and airBridge family of devices. The 
# output is in the MRTG compliant format and can be used as the 
# source. Sample configuration files are given in sample_*.cfg  
# 
#   Copyright:  2003 smartBridges Pte Ltd.
#   Author: Nikhil Goel <nikhil.goel@smartbridges.com>
#   Version : 1.2a
#
#   Please see the Changelog file for acknowledgements
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License Version 2 from
#  June 1991 as published by the Free Software Foundation.
#
#  This program is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

my $VERSION = "1.2a";
my $Percentage = 1;
my $ReverseTXRX = 0;

use Getopt::Std;
use Net::SNMP;
use strict;
	
my %opts;
getopt("-ictrp", \%opts);
my $host = $opts{'i'} || Usage();
my $community = $opts{'c'} || Usage();
my $statType = $opts{'t'} || Usage();

if ($opts{'r'}) { 
    $ReverseTXRX = $opts{'r'};
 } else {
    $ReverseTXRX =  0;
 }

if ($opts{'p'} eq "0" ) {
    $Percentage = $opts{'p'};
}



#----------------Basic Code Below-------------------------#

# SNMP Port
my $port = 161;

# Setup OIDs
my $Name = '1.3.6.1.4.1.410.1.2.1.10.0';
my $Wireless = '1.3.6.1.4.1.410.1.2.3.1.0';
my $EthRx = '1.3.6.1.4.1.410.1.1.7.1.0';
my $EthTx = '1.3.6.1.4.1.410.1.1.7.2.0';
my $ClientsNum = '1.3.6.1.4.1.410.1.2.5.1.0';
my $Media = '1.3.6.1.4.1.410.1.2.8.1.0';
my $RBytes = '0';
my $TBytes = '0';
my $WName;
my $check = '0';
my ($link, $rssi, $linkvalue);
my $MAX_RSSI = 40.0;


# Start the SNMP session
my ($session, $error) = Net::SNMP->session(
	    -hostname  => shift || $host,
             -community => shift || $community,
             -port      => shift || $port
          );

if (!defined($session)) {
# MRTG does not like the ERROR output! so why bother? 
#    printf("ERROR: %s.\n", $error);
    exit 0;
}

$WName = snmpQuery($session,$Name,0);

if ($statType eq "e") {
    $RBytes = snmpQuery($session,$EthRx,1);
    $TBytes = snmpQuery($session,$EthTx,1);
}

if ( $statType eq "w" ) {
    $RBytes = snmpQuery($session,$Wireless,3);
    $TBytes = snmpQuery($session,$Wireless,2);
}

if ( $statType eq "s" ) {
    $RBytes = $TBytes = snmpQuery($session,$ClientsNum,4);
}

if ( $statType eq "l" ) {

 $RBytes = snmpQuery($session, $Media, 4);
 $TBytes = $RBytes;

# Following decoding from EARL - <earl@uphi.net> #
my $rxlb = hex(substr($RBytes, 23, 1));
my $rxhb = hex(substr($RBytes, 22, 1));

my $txlb = hex(substr($TBytes, 31, 1));
my $txhb = hex(substr($TBytes, 30, 1));

$RBytes = $rxlb + $rxhb * 16;
$TBytes = $txlb + $txhb * 16;
# End of decoding

# Brief explanation:
# The MAX_RSSI for smartBridges radios is 40. This is a baseband processor
# default, and is used for calculation of the Roaming threshold and
# other parameters in the operaion of the channel. The different values
# are also used for RSSI in a relative manner for other functions. For
# the purpose of representation, the MAX_RSSI is scaled as per the Radio
# to show a percentage value. In dBm, the same would range from -95 dBm
# to -10 dBm. In the next few lines we just conver the RSSI value to a
# percentage. To disable; specify "-p 0" in the command line.

 if ( $Percentage == 1 ) {
   $rssi = $RBytes;
   $link = $TBytes;
   if ($rssi > $MAX_RSSI) {
     $rssi = 40;
   }
   if ($link > $MAX_RSSI) {
     $link = 40;
   }

   # what if the link quality value returned is Zero?
   if ($link == 0) {
     $linkvalue = $link;
   } else {
     $linkvalue = ($MAX_RSSI - $link);
   }
   $RBytes = ( $rssi / $MAX_RSSI ) * 100;
   $TBytes = ( $linkvalue / $MAX_RSSI ) * 100;
 }

}

if ($ReverseTXRX == 1) {
    print $TBytes."\n";
    print $RBytes."\n";
} else {
    print $RBytes."\n";
    print $TBytes."\n";
}
    print "--\n";
    print $WName."\n";

# All Done. Close.
$session->close;
exit 0;

#The actual query control, depending on the type.
sub snmpQuery() {
    my ($session, $result,$resultval,@values,$retval,@Rest,$query,$type);
    ($session,$query,$type) = @_;
    $result = $session->get_request(
				    -varbindlist => [$query]
				    );
#
# The error check is important, more so, if the values
# returned is not correct. This messes up the logs!
#
    if (!defined($result)) {
#
# Ideally this should be handled by the MRTG properly.
#	printf("ERROR: %s.\n", $session->error);
	$session->close;
# Though its wrong to return '0' as exit code for an error, we'd
# do this so that MRTG behaves.
	return;
	exit 0;
    }

    $resultval = $result->{$query};
    if ( $type == 0 ) {
	(@Rest) = split(" ",$resultval);
	($retval,@Rest) = reverse(@Rest);
    }
    if ( $type == 1 ) {
	@values = hexString($resultval);
	($retval,@Rest) = @values;
    } 
    if ( $type == 2 ) {
	@values = hexString($resultval);
	my ( $UTPax, $BTPax, $MTPax, $TBecon, $TACK, $TRTS, $TCTS, $URPax, $BRPax, $MRPax, @Rest) = @values;
	$retval = $UTPax + $BTPax + $MTPax;	
    }
    if ( $type == 3 ) {
	@values = hexString($resultval);
	my ( $UTPax, $BTPax, $MTPax, $TBecon, $TACK, $TRTS, $TCTS, $URPax, $BRPax, $MRPax, @Rest) = @values;
	$retval = $URPax + $BRPax + $MRPax;	
    }
    if ($type == 4 ){
	$retval = $resultval;
    }
    return $retval;
}


# For the case of the Hex-String, the string needs to be broken into
# the octets, and they are read in reverse.
sub hexString() {
    my (@vals,$dList,@Rest,$length,$i);
    ($dList,@Rest) = @_;
    $length = length($dList);

# Sanitizing by removing the 0x character first.
    $dList = substr($dList,2,$length);
    $length = $length - 2;
# Quick and dirty extraction of values.
    $i=0;
    while ($i<$length) {
	my $val = "";
	my $k = 6;
	do {
	    my $Temp = substr($dList,$i+$k,2);
	    $val = $val.$Temp;
	    $k = $k - 2;
	} while ($k >-1);
	$i = $i+8;
	push @vals, hex($val);
    }
    return @vals;
}

sub Usage() {

	print STDERR "sb-mrtg.pl 1.2a Copyright (c) 2003 smartBridges Inc.
Prints out the requisite information from the wireless device, compatible with the MRTG Logs parser.

USAGE: sb-mrtg.pl -i <AP Address> -c <Community String> -t <Statistics Type> -r <Output Order(Optional)>

	-i		- The Host address/IP address of the AP.
	-c	         - The community string | Password on the AP.
	-t{e|w|s}	- Can be either if the following: 
                               e for Ethernet Ports Statistics
                               w for Wireless Ports Statistics
                               s for Number of Associated Stations
         -r {1|0}          - Reverse the output order, default is RX and then TX
                               1 for Reverse to Tx/Rx
                               0 Default, Maintain Rx/Tx\n";

	exit (1);
}


