#!/usr/bin/perl -w use strict; use FileHandle; use integer; # A Small but Useful (tm) utility to do checksums for firmware for the # NWR04B router. Can do either Network Everywhere checksum, or Repotec/ # Runtop/Lanware checksums. Expects as arguments: # # your application.bin.gz # the name of the bootloader # # The new image is spat to STDOUT. # # Copyright 2005 Hugh Brown. Released under version 2 of the GPL. # # # $Id$ # Okay, so here's the structure of the checksum: # # 0x00: branch ahead # 0x04: unknown # 0x08: unknown # 0x0c: version number. # 0x10: unknown # 0x14: image length - 32 (0x20) (ie, bootloader + application.bin.gz) # 0x18: sum of bytes with offset 32 (0x20) into file (ie, bootloader + application.bin.gz) # 0x1c: sum of bytes from 0x04 through 0x1b # # The Network Everywhere firmware does this only once, then some additional lengths at # the end of bootloader. The Repotec/Runtop/Lanware firmware repeats the checksum at # offset 32, with the offsets for 0x34 and 0x38 being 64 bytes (0x40). sub checksum { my ($buf_ref, $offset, $length) = @_; my ($i, $sum); $sum = 0; for ($i = 0; $i < $length; $i++) { my $byte = unpack ('C', substr ($$buf_ref, $offset + $i, 1)); #$sum = ($sum + $byte) %256; $sum += $byte; } return $sum; } if ($ARGV[0] eq "-h") { print "FIXME: Help goes here.\n"; print "For right now:\n"; print "checksum [application.bin.gz] [bootloader]\n"; exit; } my $app = $ARGV[0]; my $app_data; my $app_length = (stat($app))[7]; my $bootloader = "bootloader"; if ($ARGV[1]) { $bootloader = $ARGV[1]; } my $boot_length = (stat($bootloader))[7]; my $boot_data; #my $offset = $length - 12; my $fd = new FileHandle; my $combined_data; my $sum; my $second_sum; my $length; $fd->open("<$app") or die ("Can't open $app for reading: $!"); $fd->read($app_data, $app_length); $fd->close(); $fd->open("<$bootloader") or die ("Can't open $bootloader for reading: $!"); $fd->read($boot_data, $boot_length); $fd->close(); $combined_data = $boot_data . $app_data; # Need to do second checksum first. $length = $boot_length + $app_length - 64; $sum = checksum (\$combined_data, 64, $length); $sum = pack ("V", $sum); $length = pack ("V", $length); $sum = $length . $sum; substr ($combined_data, 52, 8, $sum); $sum = checksum (\$combined_data, 36, 24); $sum = pack ("V", $sum); substr ($combined_data, 60, 4, $sum); # Now the first checksum: $length = $boot_length + $app_length - 32; $sum = checksum (\$combined_data, 32, $length); $sum = pack ("V", $sum); $length = pack ("V", $length); $sum = $length . $sum; substr ($combined_data, 20, 8, $sum); $sum = checksum (\$combined_data, 4, 24); $sum = pack ("V", $sum); substr ($combined_data, 28, 4, $sum); print $combined_data; exit; #$fd->open("<$bootloader") or die ("Can't open $bootloader for reading: $!"); #$fd->read($boot_data, $boot_length); #$fd->close(); #substr ($boot_data, -12, 8, "$length$sum"); #print $boot_data; #print $data;