#!/usr/bin/perl
# rp2c_cfg_rcvr, Boone, 02/23/11
# Pretend to be an Icom ID-RP2C repeater controller to the config program
#
# Modifications:
# 02/23/11 Boone      Initial coding
# 02/24/11 Boone      Add password set transaction, make variable sets
#                     actually change our stored values, test for non-empty
#                     register string values, not truth: values can be zero,
#                     comments on mac address ranges
# 03/01/11 Boone      Set responses for d and x registers swap to lower
#                     case on real hardware; adjustments to default values;
#                     rig command line for setting ips/macs; comments
# End Modifications

# Libraries

	use Socket;

# Initialize

	$port = 20319;
	$proto = getprotobyname('udp');
	$paddr = sockaddr_in($port, INADDR_ANY);
	socket(SH, PF_INET, SOCK_DGRAM, $proto) ||
		die "unable to create socket: $!";
	bind(SH, $paddr) ||
		die "unable to bind socket: $!";

	%fl =
	(
		i1	=> '"V0301   "',
		i2	=> '"V0301   "',
		i3	=> '"V0301   "',
		i4	=> '"V0301   "',
		i5	=> '"V0200   "',
	);

	%rd =
	(
		d001	=> '20319',
		d100	=> '1',
		d101	=> '1',
		d102	=> '323',
		d103	=> '322',
		d104	=> '0',
		d105	=> '321',
		d106	=> '0',
		d107	=> '0',
		d108	=> '1',
		d110	=> '20000',
		s000	=> '"XXXXXXXX"',
		s001	=> '"RPT000  "',
		x000	=> 'ac100001',			# RP2C IP address
		x002	=> 'ffffff00',
		x003	=> '00000000',
		x004	=> '001a92b2',			# This range assigned to Icom
		x005	=> '00b2b581',
		x109	=> 'ac100014',
		x111	=> '0000222e',			# This range assigned to maintech GmbH
		x112	=> '00000005',
		x113	=> '010001fd',			# This range assigned to DVSI (AMBE)
		x114	=> '0100080e',
		x115	=> 'ff010000',
		x116	=> 'ff050000',
	);
#		x004	=> '000090c7',			# This range assigned to Icom
#		x005	=> '00a004e7',

	%st =
	(
		x001	=> '0000002',
	);

# Command line

	foreach $arg (@ARGV)
	{
		if (! $ctlip)
		{
			$rd{x000} = $arg;						# Controller IP
			next;
		}
		if (! $ctlnm)								# Controller netmask
		{
			$rd{x002} = $arg;
			next;
		}
		if (! $gwip)								# Gateway IP
		{
			$rd{x109} = $arg;
			next;
		}
		die "don't know what to do with arg $arg";
	}

# Listen

	while ($src = recv(SH, $buf, 64, 0))
	{
		($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
			localtime(time);
		($srcport, $srcip) = unpack_sockaddr_in($src);
		chop($buf);
		printf(STDERR "%04d-%02d-%02d %02d:%02d:%02d %03d %s:%d recv [%s]\n",
			$year+1900, $mon+1, $mday, $hour, $min, $sec, length($buf),
			inet_ntoa($srcip), $srcport, $buf);
		$resp = &response($buf);
		if ($resp)
		{
			send(SH, $resp, 0, $src);
			chop($resp);
			printf(STDERR
				"%04d-%02d-%02d %02d:%02d:%02d %03d %s:%d send [%s]\n",
				$year+1900, $mon+1, $mday, $hour, $min, $sec, length($buf),
				inet_ntoa($srcip), $srcport, $resp);
		}
	}

# How did I get here!?

	exit(0);

# Build an appropriate response

	sub response
	{
		my $cmd = shift;
		my $resp;

		$op = substr($cmd, 1, 1);
		$subcmd = substr($cmd, 2, 2);
		$setphrase = substr($cmd, 5);
		if ($setphrase =~/^[dx]/)
		{
			$setphrase =~ y/A-F/a-f/;
		}
		($register, $value) = ($setphrase =~ /([^=]+)=(.*)/);
		$rest = substr($cmd, 2);

		$resp = 'br';
		if		($op eq '!')				# Fake: for injecting comments w/nc
		{
			$resp = "Comment injected\n";
		}
		elsif	($op eq 's')				# Set/Execute ops; we echo most
		{
			if		($subcmd eq 'LI')		# Login
			{
				$resp .= "LI:OK\r";
			}
			elsif	($subcmd eq 'PC')
			{
				$resp .= "PC:ACK\r";
			}
			elsif	($subcmd eq 'RD')			# Routing data
			{
				$rd{$register} = $value;
				$resp .= $subcmd;
				$resp .= ':';
				$resp .= $setphrase;
				$resp .= "\r";
			}
			elsif	($subcmd eq 'SV')			# Save to flash
			{
				$resp .= "SV:ACK\r";
			}
			elsif	($subcmd eq 'EX')			# Execute a function
			{
				if		($setphrase eq 'x000')		# Reboot
				{
					$resp = '';
				}
				else
				{
					warn "execute register [$register] not understood";
					$resp = '';
				}
			}
			else								# Case we haven't seen before
			{
				warn "subcommand [$subcmd] not understood";
				$resp = '';
			}
		}
		elsif	($op eq 'd')				# Display ops; we make stuff up
		{
			if		($subcmd eq 'FL')			# Firmware level
			{
				if ($fl{$setphrase} ne "")
				{
					$resp .= 'FL:';
					$resp .= $setphrase;
					$resp .= '=';
					$resp .= $fl{$setphrase};
					$resp .= "\r";
				}
				else
				{
					warn "firmware level register [$register] not understood";
					$resp = '';
				}
			}
			elsif	($subcmd eq 'RD')			# Routing data
			{
				if ($rd{$setphrase} ne "")
				{
					$resp .= 'RD:';
					$resp .= $setphrase;
					$resp .= '=';
					$resp .= $rd{$setphrase};
					$resp .= "\r";
				}
				else
				{
					warn "radio data register [$setphrase] not understood";
					$resp = '';
				}
			}
			elsif	($subcmd eq 'ST')			# Status
			{
				if ($st{$setphrase} ne "")
				{
					$resp .= 'ST:';
					$resp .= $setphrase;
					$resp .= '=';
					$resp .= $st{$setphrase};
					$resp .= "\r";
				}
				else
				{
					warn "status register [$setphrase] not understood";
					$resp = '';
				}
			}
			elsif	($subcmd eq 'VS')			# Firmware Version
			{
				$resp .= "VS:Revision1.2\r";
			}
			else
			{
				warn "subcommand [$subcmd] not understood";
				$resp = '';
			}
		}
		else								# Case we haven't seen before
		{
			warn "opcode [$op] not understood";
			$resp = '';
		}

		return($resp);
	}
