#!/usr/bin/perl # use IO::Socket::INET; use Socket; use strict; use warnings; sub usage() { print STDERR "Usage: $0 [firmware.bin]\n\n"; exit 0; } my $ip = shift @ARGV; $ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage(); my $probe = IO::Socket::INET->new(Proto => 'udp', Broadcast => 1, LocalAddr => '192.168.0.2', LocalPort => 5035) or die "socket: $!"; my $setip = unpack("N", inet_aton($ip)); $setip > 0 or usage(); my @packets; foreach my $ver ([18, 1], [22, 2]) { push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0); } print STDERR "Looking for device: "; my $broadcast = sockaddr_in(5035, INADDR_BROADCAST); my $scanning; my $box; $SIG{"ALRM"} = sub { return if --$scanning <= 0; foreach my $packet (@packets) { $probe->send($packet, 0, $broadcast); } print STDERR "."; }; $scanning = 10; foreach my $packet (@packets) { $probe->send($packet, 0, $broadcast); } print STDERR "."; while($scanning) { my $reply; alarm(1); if (my $peer = $probe->recv($reply, 16)) { next if (length($reply) < 16); my ($port, $addr) = sockaddr_in($peer); my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply); $addr2 = pack("N", $addr2); if ($code == 2) { $scanning = 0; printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2); $box = inet_ntoa($addr); } } } $box or die " not found!\n"; { package ADAM2FTP; use base qw(Net::FTP); # ADAM2 requires upper case commands, some brain dead firewall doesn't ;-) sub _USER { shift->command("USER",@_)->response() } sub _GETENV { my $ftp = shift; my ($ok, $name, $value); $ftp->command("GETENV",@_); while(length($ok = $ftp->response()) < 1) { my $line = $ftp->getline(); unless (defined($value)) { chomp($line); ($name, $value) = split(/\s+/, $line, 2); } } $ftp->debug_print(0, "getenv: $value\n") if $ftp->debug(); return $value; } sub getenv { my $ftp = shift; my $name = shift; return $ftp->_GETENV($name); } sub _REBOOT { shift->command("REBOOT")->response() == Net::FTP::CMD_OK } sub reboot { my $ftp = shift; $ftp->_REBOOT; $ftp->close; } } my $file = shift @ARGV; $file || exit 0; my $ftp = ADAM2FTP->new($box, Debug => 1, Timeout => 600) or die "can't open control connection\n"; $ftp->login("adam2", "adam2") or die "can't login\n"; my $mtd5 = $ftp->getenv("mtd5"); my ($ksize); $mtd5 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1); $ksize or die 'cannot read partition offsets'; printf STDERR "Available flash space: 0x%08x\n", $ksize; open FILE, "<$file" or die "can't open firmware file\n"; $ftp->command("MEDIA FLSH")->response(); $ftp->binary(); print STDERR "Writing to mtd5...\n"; my $dc = $ftp->stor("fs mtd5"); $dc or die "can't open data connection\n"; my $rbytes = 1; while (($ksize > 0) and ($rbytes > 0)) { my $buffer; my $len = ($ksize > 1024 ? 1024 : $ksize); $rbytes = read FILE, $buffer, $len; $rbytes and $ksize -= $dc->write($buffer, $rbytes, 600); } $dc->close(); print "Rebooting...\n"; $ftp->reboot();