#!/usr/bin/perl

# This script will retrieve the status of a Broadxtend DSL Modem.
# Tested with a Covad/Speakeasy provided 8012V.
#
# Usage: run it on a system that is directly connected to the modem.
# 
# if you provide 'Y' as a paramter, debug information will be printed
# as well.
#
#  please send any feedback to 'jullrich@euclidian.com'. This
# software is provided 'as is'. Feel free to share it.
# If you find inconsistencies, please send me the output of
# ./broadband_blaster.pl and if possible the logfile for the
# windows application 'broadband_blaster' which is provided
# with the modem.
#
#

use IO::Socket;

$debug=shift||'N';

$client_port='62827';
$server_port='62828';


die ("cant fork: $!") unless defined($kidpid=fork());

if ( $kidpid) {
$SIG{INT}=sub { kill("TERM"=>$kidpid) };
$data1='71 ED F5 64 14 d5 42 4f 99 12 5c e8 04 8b e4 2b 01 00 01 00 02 00 00 00';
$data2='00 00 ac 00 00 00 6c f5 00 00 00 b0 d0 77 4e 04 00 e0 eb 74 df c0 1e 00 00 00 32 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 12 00 00 00 33 00 00 00 37 00 00 00 38 00 00 00 39 00 00 00 3a 00 00 00 3b 00 00 00 3c 00 00 00 3d 00 00 00 3e 00 00 00 3f 00 00 00 40 00 00 00 41 00 00 00 42 00 00 00 43 00 00 00 44 00 00 00 45 00 00 00 46 00 00 00 47 00 00 00 48 00 00 00 49 00 00 00 4a 00 00 00 4b 00 00 00 4c 00 00 00 4d 00 00 00 4e 00 00 00';


$client_sock=IO::Socket::INET->new(Proto=>'udp',
                                   PeerPort =>$client_port,
                                   PeerAddr => '255.255.255.255',
				   Broadcast => 1 ) || die ("sock: $!");

$data1 =~ tr/ //d;
$packet1=pack('H*',$data1);
$data2 =~ tr/ //d;
$packet2=pack('H*',$data2);
  $count++;
  $highcount=int($count/256);
  $lowcount=$count-$highcount*256;
  $packet=$packet1.chr($lowcount).chr($highcount).$packet2;
  $client_sock->send($packet) || die ("send: $!");; 
sleep(1);
kill("TERM"=>$kidpid);

} else {
$server_socket=IO::Socket::INET->new(LocalPort=>$server_port,
                                     Proto=>'udp')
|| die ("couldn't setup a server on $server_port: $@ $!\n");

while ($message=$server_socket->recv($datagram,2000,$flags)) {
 print "\n\nMarker=";
 $datagram=splitprint($datagram,16,'Y');
 $datagram=splitprint($datagram,8,$debug);

 print "Seq. Number=";
 $datagram=intsplitprint($datagram,2,'Y');

 $datagram=splitprint($datagram,2,$debug);
 $datagram=splitprint($datagram,2,$debug);
$datagram=splitprint($datagram,2,$debug);

 print "BCP Send=";
$datagram=intsplitprint($datagram,2);
$datagram=splitprint($datagram,2,$debug);

 print "MAC 1=";
 $datagram=splitprint($datagram,6,'Y');
 print "MAC 2=";
 $datagram=splitprint($datagram,6,'Y');
 $datagram=splitprint($datagram,16,$debug);
 print "Firmware Version: ";
 $datagram=asciisplitprint($datagram,10);
 $datagram=splitprint($datagram,29,$debug);
 print "Vci=";
 $datagram=intsplitprint($datagram,1);
 $datagram=splitprint($datagram,2*16+15,$debug);
 print "Uptime=";
 $datagram=timesplitprint($datagram,4);
 $datagram=splitprint($datagram,3*16+13,$debug);
 print "Downstream=";
 $datagram=intsplitprint($datagram,2,256);
 $datagram=splitprint($datagram,14,$debug);
 print "Upstream=";
 $datagram=intsplitprint($datagram,2,256);

 $datagram=splitprint($datagram,13,$debug);
 print "SNR?=";
 $datagram=intsplitprint($datagram,1,1);
 $datagram=splitprint($datagram,15,$debug);
 print "SNR=";
 $datagram=intsplitprint($datagram,1,1);
 $datagram=splitprint($datagram,15,$debug);
 print "Upstream Attenuation=";
 $datagram=intsplitprint($datagram,1);
 $datagram=splitprint($datagram,15,$debug);
 print "Downstream Attenuation=";
 $datagram=intsplitprint($datagram,1);
 $datagram=splitprint($datagram,15,$debug); 
 print "Downstream Output Power=";
 $datagram=intsplitprint($datagram,1);
 $datagram=splitprint($datagram,15,$debug);
 print "Upstream Output Power=";
 $datagram=intsplitprint($datagram,1);


 $datagram=splitprint($datagram,1000,$debug);
}

}

sub splitprint {
  my $data=shift;
  my $length=shift || length($data);
  my $print=shift||'N';

  if ($print eq 'Y' ) {
  my $count=0;
  my $x=unpack("H*",substr($data,0,$length));

   foreach ( split(//,$x) ) {
    print $_;
    $count++;
    if ( $count%32==0 ) { print "\n"; } else {
      if ( $count%2==0 ) { print "-"; }
    }
  }
  print "\n";
  }
  return substr($data,$length);
}

sub asciisplitprint {
  my $data=shift;
  my $length=shift || length($data);
  my $count=0;
  my $x=unpack("H*",substr($data,0,$length));
  while ( $x!='' ) {
    $d=substr($x,0,2);
    $x=substr($x,2,length($x)-2);
    print chr(hex($d));
  }
  print "\n";
  return substr($data,$length);
}

sub intsplitprint {
  my $data=shift;
  my $length=shift || length($data);
  my $mult=shift||1;
  my $count=0;

  my $x=unpack("H*",substr($data,0,$length));
  if ( $length==2 ) { $x=substr($x,2,2).substr($x,0,2); } 
  print hex($x)*$mult."\n";
  return substr($data,$length);
}

sub timesplitprint {
  my $data=shift;
  my $length=shift || 4;
  my $x=unpack("L",substr($data,0,$length))/100;
  $day=int($x/60/60/24);
  $x=$x-$day*60*60*24;
  $hr=int($x/60/60);
  $x=$x-$hr*60*60;
  $min=int($x/60);
  $x=$x-$min*60;
  print "$day days $hr hours $min minutes $x seconds\n";
  return substr($data,$length);
}
