#!/bin/sh
# the next line restarts using tclsh -*- tcl -*- \
exec tclsh "$0" "$@"
#
# bridge --
#
#       This example shows how to dump the forwarding table of a bridge
#	or switch which implements the BRIDGE-MIB. This example does
#	not do any fancy error handling because it is just an example.
#
# Copyright (c) 1997-1998 TU Braunschweig.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# @(#) $Id: bridge,v 1.2 1998/04/20 11:40:03 schoenw Exp $

package require Tnm
package require TnmSnmp $tnm(version)

Tnm::mib load BRIDGE-MIB

proc GetIfTable {s} {
    global ifDescr ifType ifOperStatus ifAdminStatus
    $s walk x {ifIndex ifDescr ifType ifOperStatus ifAdminStatus} {
	set ifIndex [Tnm::snmp value $x 0]
	set ifDescr($ifIndex) [Tnm::snmp value $x 1]
	set ifType($ifIndex) [Tnm::snmp value $x 2]
	set ifOperStatus($ifIndex) [Tnm::snmp value $x 3]
	set ifAdminStatus($ifIndex) [Tnm::snmp value $x 4]
    }
}

proc GetPortTable {s} {
    global dot1dBasePortIfIndex
    $s walk x {dot1dBasePort dot1dBasePortIfIndex} {
	set port [Tnm::snmp value $x 0]
	set dot1dBasePortIfIndex($port) [Tnm::snmp value $x 1]
    }
}

proc GetForwardingDatabase {s} {
    global dot1dTpFdbPort dot1dTpFdbStatus
    $s walk x {dot1dTpFdbAddress dot1dTpFdbPort dot1dTpFdbStatus} {
	set mac [Tnm::snmp value $x 0]
	set dot1dTpFdbPort($mac) [Tnm::snmp value $x 1]
	set dot1dTpFdbStatus($mac) [Tnm::snmp value $x 2]
    }
}

proc GetFilterTable {s} {
    global dot1dStaticAllowedToGoTo dot1dStaticStatus
    $s walk x {
	dot1dStaticAddress dot1dStaticReceivePort 
	dot1dStaticAllowedToGoTo dot1dStaticStatus
    } {
	set mac [Tnm::snmp value $x 0]
	set port [Tnm::snmp value $x 1]
	set dot1dStaticAllowedToGoTo($mac,$port) [Tnm::snmp value $x 2]
	set dot1dStaticStatus($mac,$port) [Tnm::snmp value $x 3]
    }
}

proc PrintTables {s} {
    global dot1dBasePortIfIndex
    global dot1dTpFdbPort dot1dTpFdbStatus
    global dot1dStaticAllowedToGoTo dot1dStaticStatus
    global ifDescr ifType ifOperStatus ifAdminStatus

    if [info exists dot1dBasePortIfIndex] {
	foreach port [lsort -integer [array names dot1dBasePortIfIndex]] {
	    set ifIndex $dot1dBasePortIfIndex($port)
	    puts [format "Port #%3d Interface #%3d %16s %8s %8s (%s)" \
		    $port $ifIndex $ifType($ifIndex) \
		    $ifOperStatus($ifIndex) $ifAdminStatus($ifIndex) \
		    $ifDescr($ifIndex)]
	}
	puts ""
	
	foreach port [lsort -integer [array names dot1dBasePortIfIndex]] {
	    foreach mac [array names dot1dTpFdbPort] {
		if {$dot1dTpFdbPort($mac) == $port} {
		    puts [format "Port #%3d %20s %s" $port $mac \
			    $dot1dTpFdbStatus($mac)]
		}
	    }
	}
    }

    if [info exists dot1dStaticAllowedToGoTo] {
	puts ""
	foreach macport [array names dot1dStaticAllowedToGoTo] {
	    set mac  [lindex [split $macport ,] 0]
	    set port [lindex [split $macport ,] 1]
	    puts -nonewline [format "Port #%3d filters %18s"  $port $mac]
	    if {$dot1dStaticAllowedToGoTo($macport) == "00"} {
		puts " on all ports ($dot1dStaticStatus($macport))" 
	    } else {
		set ports ""
		regsub -all : $dot1dStaticAllowedToGoTo($macport) {} bits
		set bits [binary scan [binary format H* $bits] B* bits]
		for {set i 0} {$i < [string length $bits]} {incr i} {
		    if {[string index $bits $i]} {
			lappend ports [expr $i + 1]
		    }
		}
		puts " on port(s) $ports ($dot1dStaticStatus($macport))"
	    }
	}
    }
}

proc SetFilter {s mac {port 0}} {
    set index $mac.$port
    catch {$s set [list [list dot1dStaticStatus:$index invalid]]}
    lappend vbl [list dot1dStaticAddress:$index $mac]
    lappend vbl [list dot1dStaticReceivePort:$index $port]
    lappend vbl [list dot1dStaticAllowedToGoTo:$index 00]
    lappend vbl [list dot1dStaticStatus:$index deleteOnReset]
    if [catch {$s set $vbl} msg] {
	error $msg
    }
}

foreach ip $argv {
    set s [Tnm::snmp generator -address $ip]
    $s bind recv { puts -nonewline stderr "." }
    GetIfTable $s
    GetPortTable $s
    GetForwardingDatabase $s
    GetFilterTable $s
    #SetFilter $s 01:02:03:04:05:06
    $s bind recv {}; puts stderr ""
    PrintTables $s
    $s destroy
}
