# SNMPAgent.pm
#
# Object for handling SNMP requests as per draft-ietf-radius-servmib-04.txt
#
# Author: Mike McCauley (mikem@open.com.au)
# Copyright (C) 1997 Open System Consultants
# $Id: SNMPAgent.pm,v 1.2 1999/02/21 22:26:49 leinen Exp $

use SNMP_Session "0.68";
use SNMP_util;
use Socket;

$port = SNMP_Session::standard_udp_port;
$session = SNMP_Session->open('0.0.0.0', '', 
			      $port, undef, $port);


while (1)
{
    &handle_socket_read();
}

#####################################################################
# This function is called whenever there is a packet waiting to
# be read from the SNMP port
sub handle_socket_read
{
    my ($fileno) = @_;

    my ($request, $iaddr, $port) = $session->receive_request();
    if (defined $request)
    {
	my ($type, $requestid, $bindings, $community) 
	    = $session->decode_request($request);
	
	print "SNMPAgent: received request $type, $requestid, $community\n";

	my ($error, $errorstatus, $errorindex);
	$errorstatus = $errorindex = 0;

	# Check the community
	if ($community ne 'public')
	{
	    print "SNMPAgent: wrong community: $community. Ignored\n";
	    return;
	}
	my $index = 0;

	my @results;
	binding: while (!$errorstatus && $bindings ne '') 
	{
	    my $binding;
	    ($binding, $bindings) = BER::decode_sequence($bindings);
	    while (!$errorstatus && $binding ne '')
	    {
		($b, $binding) = BER::decode_sequence($binding);
		$index++;
		if ($type == SNMP_Session::get_request)
		{
		    # SAMPLE code only:
		    my ($oid) = BER::decode_oid($b);  # Binary oid
		    my $poid = BER::pretty_oid($oid);
		    print "get request for $poid\n";
		    my $value = BER::encode_int(12345);
		    push(@results, BER::encode_sequence($oid, $value));
		}
		elsif ($type == SNMP_Session::getnext_request)
		{
		    # SAMPLE code only:
		    my ($oid) = BER::decode_oid($b);  # Binary oid
		    my $poid = BER::pretty_oid($oid);
		    print "getnext request for $poid\n";

		    # fake up the next oid by just incrementing
		    @fromoid = split(/\./, $poid);
		    $fromoid[-1]++;
		    print "changed to @fromoid\n";
		    $oid = BER::encode_oid(@fromoid);
		    my $value = BER::encode_int(12345);
		    push(@results, BER::encode_sequence($oid, $value));
		}
		elsif ($type == SNMP_Session::set_request)
		{
		    # SAMPLE code only:
		    my ($oid, $value) = BER::decode_by_template($b, "%O%@");
		    my $poid = BER::pretty_oid($oid);
		    ($value) = BER::decode_int($value);
		    print "set request for $poid to $value\n";
		    $value = BER::encode_int($value);
		    push(@results, BER::encode_sequence($oid, $value));

		}
		else
		{
		    warn "SNMPAgent: error decoding request: " . $BER::errmsg;
		    return;
		}
		if ($errorstatus)
		{
		    $errorindex = $index;
		    last binding;
		}
	    }
	}

	# OK we've got everything they asked for, so return it
	$request = BER::encode_tagged_sequence(SNMP_Session::get_response,
					     BER::encode_int($requestid),
					     BER::encode_int($errorstatus), 
					     BER::encode_int($errorindex),
					     BER::encode_sequence(@results))
	    || warn "SNMPAgent: error encoding reply: " . $BER::errmsg;

	$session->{remote_addr} = Socket::pack_sockaddr_in($port, $iaddr);
	$session->{community} = $community;
	$request = $session->wrap_request($request);
	# tell the session where to send the reply to
	$session->send_query($request)
	    || warn "SNMPAgent: error sending reply: $!";
    }
    else
    {
	warn "SNMPAgent: receive_request failed: $!";
    }
}

1;
