use IO::Socket;
use IO::Socket::INET;

# Make a socket for network communications.
$handle = IO::Socket::INET->new(Proto => 'udp')
    or die "socket: $@";     # yes, it uses $@ here

# Prepare for network broadcast.
setsockopt($handle, SOL_SOCKET, SO_BROADCAST, 1) or die "sockopt: $!";

# Broadcast address is everyone.
$HOSTNAME="255.255.255.255";

# Lantronics XPORT special port for replying to unit search.
$PORTNO=30718;

# Prepare IP and Port number for use later.
$ipaddr   = inet_aton($HOSTNAME);
$portaddr = sockaddr_in($PORTNO, $ipaddr);

# Put data into the proper format for sending over the network.
#  N = An unsigned long (32-bit) in "network" (big-endian) order.
#  f6 = the request recognized by the Lantronix X-Port module.
$Request = pack("N", 0x000000f6);

# Send the broadcasted search for units.
send($handle, $Request, 0, $portaddr) == length($Request)
        or die "cannot send to $HOSTNAME($PORTNO): $!";

# Identify the length of expected replies.
$MAXLEN=30;

# Encapsulate in eval so that timeout can interrupt the reception.
eval {
	local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
	#Set timeout in seconds
	alarm 2;
	
	# Keep adding response characters to string
	while (1){
		# Receive one packet
		$portaddr = recv($handle, $ReceivedMessage, $MAXLEN, 0)      or die "recv: $!";
		
		# Gather information from received packet.
		($portno, $ipaddr) = sockaddr_in($portaddr);
		
		# Convert IP address to a string and print it.
		print "IP=".inet_ntoa($ipaddr)."\tMAC=";
		
		# Pull MAC from message, convert HEX to ASCII and print it.
		if (substr($ReceivedMessage,3,1) eq chr(0xf7)) {
			foreach (23 .. 29) {
				printf "%X",ord(substr($ReceivedMessage,$_,1));
			}
			print "\n";
		}
	}
	alarm 0;
};
