#!/usr/bin/perl
use strict;
use warnings;

use Net::Frame::Layer qw(:subs);

my $target = shift || die("Specify target IPv6 address\n");
my $dev    = shift;

if ($target) {
   $target = getHostIpv6Addr($target) || die("Unable to revolv hostname\n");
}

use Net::Frame::Device;
use Net::Frame::Simple;
use Net::Frame::Layer::ETH qw(:consts);
use Net::Frame::Layer::IPv6 qw(:consts);
use Net::Frame::Layer::ICMPv6 qw(:consts);
use Net::Frame::Layer::ICMPv6::NeighborSolicitation;

my $oDevice;
if ($dev) {
   $oDevice = Net::Frame::Device->new(target6 => $target, dev => $dev);
}
else {
   $oDevice = Net::Frame::Device->new(target6 => $target);
}

use Net::Frame::Dump::Online;
my $oDump = Net::Frame::Dump::Online->new(
   dev    => $oDevice->dev,
   filter => 'icmp6',
);
$oDump->start;

require Net::IPv6Addr;
my $target6 = Net::IPv6Addr->new($target)->to_string_preferred;
my @dst = split(':', $target6);
my $str = $dst[-2];
$str =~ s/^.*(..)$/$1/;
$target6 = 'ff02::1:ff'.$str.':'.$dst[-1];

#my $str2 = $dst[-1];
#$str2 =~ s/^(..)(..)$/$1:$2/;
#my $mac6 = '33:33:ff:'.$str.':'.$str2;

print $target6."\n";
#print $mac6."\n";

my $eth = Net::Frame::Layer::ETH->new(
   src  => $oDevice->mac,
   #dst  => $mac6,
   type => NF_ETH_TYPE_IPv6,
);

my $ip = Net::Frame::Layer::IPv6->new(
   src        => $oDevice->ip6,
   dst        => $target6,
   nextHeader => NF_IPv6_PROTOCOL_ICMPv6,
);

my $icmp = Net::Frame::Layer::ICMPv6->new(
   type => NF_ICMPv6_TYPE_NEIGHBORSOLICITATION,
);
my $ns = Net::Frame::Layer::ICMPv6::NeighborSolicitation->new(
   targetAddress => $target,
   options       => [
      Net::Frame::Layer::ICMPv6::Option->new(
         type   => NF_ICMPv6_OPTION_SOURCELINKLAYERADDRESS,
         length => 1,
         value  => pack('H2H2H2H2H2H2', split(':', $oDevice->mac)),
      ),
   ],
);

my $oSimple = Net::Frame::Simple->new(
   layers => [ $eth, $ip, $icmp, $ns, ],
);
print $oSimple->print."\n";

use Net::Write::Layer2;

my $oWrite = Net::Write::Layer2->new(dev => $oDevice->dev);
$oWrite->open;

my $reply;
for (1..3) {
   print 'Try number: '.$_."\n";

   $oWrite->send($oSimple->raw);

   until ($oDump->timeout) {
      if ($reply = $oSimple->recv($oDump)) {
         last;
      }
   }
   last if $reply;
   $oDump->timeoutReset;
}

$oWrite->close;

if ($reply) {
   print 'RECV:'."\n".$reply->print."\n" if $reply;
   for ($reply->ref->{'ICMPv6::NeighborAdvertisement'}->options) {
      if ($_->type eq NF_ICMPv6_OPTION_TARGETLINKLAYERADDRESS) {
         my $mac = unpack('H*', $_->value);
         print convertMac($mac)."\n";
      }
   }
}

END { $oDump && $oDump->isRunning && $oDump->stop }
