#!/usr/bin/perl

exit if fork;

use Socket;

$DEVICE = "ats";

$TIMEOUT = 1;

$SILENT_TIMEOUT = 5;

@silent_ouis = (
);

@ouis = (
"00:01:3e",
"00:13:02",
"00:02:b3", 
"00:03:47", 
"00:04:23", 
"00:07:e9",
"00:0c:f1",
"00:0e:0c",
"00:0e:35",
"00:11:11",
"00:12:f0",
"00:13:20",
"00:13:ce",
"00:13:e8",
"00:15:00",
"00:15:17",
"00:15:70",
"00:16:6f",
"00:16:76",
"00:16:ea",
"00:16:eb",
"00:18:de",
"00:19:d1",
"00:19:d2",
"00:20:7b",
"00:23:68",
"00:90:27",
"00:a0:c9",
"00:a0:f8",
"00:aa:00",
"00:aa:01",
"00:aa:02",
"00:d0:b7",
"5c:0e:8b");

$count = 0;

socket RAW, PF_INET, SOCK_RAW, 1 or die "Unable to open ping socket: $!";
# type       1b
# code       1b
# checksum   2b
# identifier 2b
# seq        2b
# data       ...
$pingpacket = pack "CCnn", 0x08, 0x00, 0xe5c5, 0xabcd, 0x0001;
$pingpacket .= "abcdefghijkl";

for (;;) {
    ###
    # Loop
    ###
    open ARP, "/sbin/ip neigh show dev $DEVICE |" or die "Unable to run 'ip neigh':$!";

    # Parse
    while ($line = <ARP>) {
        # 10.0.0.20 lladdr 00:08:83:f2:9d:00 nud reachable

        foreach $oui (@ouis)
        {
            if ( $line=~/^(\S+)\s+\S+\s+($oui)/ )
            {
                my $ip = $1;

                # Ping
                ping($ip);
                last;
            }
        }


        # Repeat for the 'silent_ouis'
        if (($count % $SILENT_TIMEOUT) == 0)
        {
            foreach $oui (@silent_ouis)
            {
                if ( $line=~/^(\S+)\s+\S+\s+($oui)/ )
                {
                    my $ip = $1;
                                                   
                    # Ping
                    ping($ip);
                    last;
                }
            }
        }
    }    

    close ARP;

    select undef, undef, undef, $TIMEOUT;
    
    $count = $count + 1;
}

sub ping($) {
    my ($ip) = @_;

    my $ip_n = inet_aton($ip);
    my $to = sockaddr_in(IPPROTO_ICMP, $ip_n);

    send RAW, $pingpacket, 0, $to or die "Unable to send ping: $!";
}

