diff --git a/hp2101nw_connect.pl b/hp2101nw_connect.pl
new file mode 100755
index 0000000000000000000000000000000000000000..d05ab490674390767aae3c2eba02ec649da060ca
--- /dev/null
+++ b/hp2101nw_connect.pl
@@ -0,0 +1,880 @@
+#!/usr/bin/perl
+## hp2101nw_connect.pl - version 0.01
+## 
+## Linux connection utility for the HP 2101nw wireless G USB print server.
+##
+## (C) 2012 Reinhold Kainhofer <reinhold@kainhofer.com>
+## License: GPL v2 or later
+
+## This script (hp2101nw_connect.pl) provides a relatively easy way to identify and
+## connect to the HP 2101nw wireless USB print server on linux.
+## The device is not a real print server, but rather a USB port forwarder
+## over TCP/UDP. On Windows it creates a virtual USB port, so for Linux
+## support, we'll need a proper kernel module doing the USB port forwarding...
+##
+## This script "only" detects the device on the network, retrieves information and
+## optionally lock it. Once a kernel module is ready, this is the user-space
+## part of the driver.
+##
+## For the device protocol see:
+## http://wiki.kainhofer.com/hardware/hp2101nw_wlan_printserver
+
+## Supported devices:
+##    -) HP 2101nw wireless G USB print server (USB-id 03f0:cd02)
+
+
+use IO::Socket;
+use IO::Select;
+# use Socket qw(:all);
+use Data::Dumper;
+use strict;
+# use warnings;
+
+our $debug=1;
+
+our $VERSION=0.01;
+print "hp2101nw_connect.pl - version $VERSION\n";
+print "Linux connection utility for the HP 2101nw wireless G USB print server.\n\n";
+print "(C) 2012 Reinhold Kainhofer <reinhold\@kainhofer.com>\n";
+print "License: GPL v2 or later\n\n";
+
+
+# The PC always identifies itself as XXXXXXXX.
+our $thisboxname = "XXXXXXXX";
+our $port_information = 34444;
+our $port_command = 34447;
+our $port_usbnet = 34448;
+
+our $SBSU_STATUS = 1;
+our $SBSU_UNKNOWN = 7;
+
+$| = 1;
+
+
+$Data::Dumper::Indent = 1;
+
+# USB vendor / product ids and descriptions of all supported devices
+my @supported_devices=(
+  [0x03f0, 0xcd02, "HP 2101nw wireless G USB print server"]
+);
+
+
+
+###############################################################################
+##  HELPER FUNCTIONS
+###############################################################################
+
+
+sub progress {
+  printf (@_);
+}
+sub debug {
+  if ($debug) {
+    printf (@_);
+  }
+}
+sub trim ($) {
+  my $string = shift;
+  $string =~ s/^\s+//;
+  $string =~ s/\s+$//;
+  return $string;
+}
+sub input () {
+  chomp (my $input = <STDIN>);
+  $input = trim ($input);
+  return $input;
+}
+sub sleep_progress ($) {
+  my $dur = shift;
+  do {
+    progress ".";
+    sleep (1);
+    --$dur;
+  } while ($dur > 0);
+  progress "\n";
+}
+
+
+
+# Give the user a number of choices to select from.
+# $text ...    text to print before the options
+# $options ... array ref containing human-readable option values (-1 for separator)
+# $values ...  array ref with option values (-1 in $options are ignored!)
+# $default ... default value if empty input is given
+sub ask_choice ($$$$) {
+  my $text = shift;
+  my $options = shift;
+  my $values = shift;
+  my $default = shift;
+  my $defindex = 0;
+  print "$text\n";
+  my $i=1;
+  foreach (@$options) {
+    if ($_ == -1) {
+      print "\t---\n";
+    } else {
+      print "\t$i) $_\n";
+      if ($values->[$i-1] eq $default) {
+        $defindex = $i;
+      }
+      ++$i;
+    }
+  }
+  my $retval;
+  do {
+    print "Your choice (default: $defindex): ";
+    my $op = input ();
+    if ($op eq "") {
+      $retval = $default;
+    } elsif (($op =~ m/^[1-9][0-9]*$/) && ($op <= scalar (@$values))) {
+      $retval = $values->[$op-1];
+    } else {
+      printf "\tInvalid input. Please enter a number from 1 to %d, or simply press Return to use the default.\n", scalar (@$values);
+    }
+  } while (!defined $retval);
+  return $retval;
+}
+
+# Ask the user for some text input, which will be validated (if invalid input
+# is given, the user is notified and asked again.
+#     $text ...      text to ask the user
+#     $validator ... callback function to validate the input
+#     $message ...   error message printed if validation fails.
+sub ask_input ($$$) {
+  my $text = shift;
+  my $validator = shift;
+  my $message = shift;
+  my $retval;
+  my $valid = 0;
+  do {
+    print $text;
+    $retval = input ();
+    $valid = &$validator ($retval);
+    if (!$valid) {
+      printf $message, $retval;
+    }
+  } while (!$valid);
+  return $retval;
+}
+
+########################
+# validation functions
+
+sub is_ip_address ($) {
+  my $ip = shift;
+  return ($ip =~ m/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/);
+}
+
+sub ask_ip_address ($) {
+  return ask_input (shift, \&is_ip_address, "\tInvalid input %s. Please enter a string of the form xxx.xxx.xxx.xxx, where each xxx is a number from 0 to 255.\n");
+}
+
+sub is_filename ($) {
+  my $fn = shift;
+  return (length($fn)>0);
+}
+
+sub is_hostname ($) {
+  return (shift =~ m/^[-A-Za-z0-9]{1,63}$/ )
+}
+
+
+
+###############################################################################
+##  USB DEVICE MANAGEMENT / COMMUNICATION FUNCTIONS
+###############################################################################
+
+sub setup_ports () {
+#   my $io_information = IO::Socket::INET->new(LocalPort => $port_information,
+#                                           Proto     => "udp");
+#   my $io_sbsu = IO::Socket::INET->new(LocalPort => $port_command,
+#                                    Proto     => "udp");
+# 
+}
+
+sub SBSU_create_buffer ($) {
+  my $cmd = shift;
+  return sprintf ("SBSU%s", pack("v", $cmd));
+}
+
+# Read data into the second argument (output argument!), return 
+# size of data
+sub SBSU_receive_data ($$$) {
+  my $sock = shift;
+  my $cmd = shift;
+
+}
+
+
+sub SBSU_status_parse ($) {
+
+}
+
+sub device_detect () {
+  my $request = SBSU_create_buffer ($SBSU_STATUS);
+  my @result = ();
+  my $loop = 0;
+  debug "Sending device detection request (UDP broadcast on port 34447)\n";
+  my $br_addr = sockaddr_in ($port_command, INADDR_BROADCAST);
+
+  my $broadcast = IO::Socket::INET->new (
+                                         PeerPort  => $port_command,
+#                                          PeerAddr  => inet_ntoa(INADDR_BROADCAST),
+                                         Proto     => 'udp',
+#                                          Listen    => 1,
+                                         Broadcast => 1 )
+      or die "Can't bind broadcast socket: $@\n";
+  my $sel = IO::Select->new( $broadcast );
+
+  while (++$loop <= 5 && scalar(@result) < 5) {
+    print ".";
+    $broadcast->send( $request, 0, $br_addr )
+        or die "Error at sending: $!\n";
+    while ($sel->can_read (1)) {
+      my $data="";
+      $broadcast->recv ($data, 8096);
+      push @result, $data;
+    }
+  }
+  print "\nResult: @result\n";
+  return @result;
+}
+
+sub device_info ($) {
+  my $ip = shift ();
+
+}
+
+sub create_status_request () {
+}
+
+sub device_open ($) {
+  my $dev = shift;
+  my $res = $dev->open;
+  if ($res<0) {
+    printf "ERROR opening device (%d): %s\n", $res, $!;
+  }
+  $res = $dev->detach_kernel_driver_np(0);
+  # No error check, Linux always gives an error!
+  $res = $dev->set_configuration(1);
+  if ($res<0) {
+    printf "ERROR setting configuration 1 (%d): %s\n", $res, $!;
+  }
+  $res = $dev->claim_interface(0);
+  if ($res<0) {
+    printf "ERROR claiming interface 0 (%d): %s\n", $res, $!;
+  }
+}
+
+sub device_close ($) {
+  my $dev = shift;
+  $dev->release_interface(0);
+  $dev->reset;
+}
+
+
+
+sub bulk_data_write ($$$) {
+  my $dev = shift;
+  my $data = shift;
+  my $len = shift;
+  # Add the header (12 bytes): '@\0', packet length, boxname (="XXXXXXXX") 
+  my $request = sprintf ("@\0%s%s%s", pack ("v", $len), $thisboxname, $data);
+  debug "Request: $request\n";
+  my $res = $dev->bulk_write (1, $request, length($request), 500);
+  if ($res<0) {
+    printf "ERROR write bulk data (%d): %s\n", $res, $!;
+  }
+  return $res;
+}
+
+# Read USB bulk data into the second argument (output argument!), return 
+# size of data
+sub bulk_data_read ($$$) {
+  my $dev = shift;
+  # TODO: Get rid of the length argument, simply read all that is sent
+  # FIXME: Read bulk data in loops until there is nothing left to read?
+  my $len = $_[1];
+  my $readdata = "";
+  my $res = $dev->bulk_read (2, $readdata, $len+13, 500);
+  if ($res<0) {
+    printf "ERROR reading bulk data (%d): %s\n", $res, $!;
+    return;
+  }
+  if ($res == 0) {
+    debug "\tEmpty response received\n";
+    return 0;
+  }
+  debug ("read %d bytes: \n%s\n\n", $res, $readdata); 
+  # Check and cut off the header after some sanity checks:
+  if (substr ($readdata, 0, 3) ne "\@\0\0") {
+    printf "ERROR reading data: Wrong header %s\n", substr ($readdata, 0, 3);
+  }
+  my $datalen = unpack ("v", substr ($readdata, 3, 2));
+  $res = $res-13;
+  if ($datalen != $res) {
+    printf "ERROR reading data: Expected %d bytes of data, got %d\n", $datalen, $res;
+  }
+  my $boxname = substr ($readdata, 5, 8);
+  # FIXME: Check the name of the box...
+  
+  # cut off the header:
+  $_[0]=substr ($readdata, 13);
+  return $res;
+}
+
+sub device_reset ($) {
+  my $dev = shift;
+  progress "Resetting the device, please wait";
+  my $res = bulk_data_write ($dev, "9002:\n", 6);
+  debug "\tSent 9002 reset command: %d\n", $res;
+  my $reset_done = 0;
+  # Poll the device until it doesn't respond. Then sleep for ~15 seconds
+  do {
+    my $readdata = "";
+    $res = $dev->bulk_read (2, $readdata, 13, 100);
+    debug "\tData received: $readdata (len: $res)\n";
+    sleep (1);
+  } while ($res > 0);
+  sleep_progress (20);
+  device_close ($dev);
+  progress "Device was reset. Please press Return.";
+  <STDIN>;
+}
+
+
+###############################################################################
+##  DEVICE CONFIGURATION HANDLING
+###############################################################################
+
+
+sub print_current_configuration ($$) {
+  my $config = shift;
+  my $text = shift;
+  sub val ($$) {
+    my $config = shift;
+    my $var = shift;
+    foreach my $e (@$config) {
+      return $e->[2] if ($e->[0] eq $var);
+    }
+    return undef;
+  }
+  progress $text;
+  printf "\tDevice name:   %s\n", val($config, '0001');
+  if (val($config,'0012') ne "Enable") {
+    printf "\tTCP/IP not yet configured and/or enabled.\n\n";
+    return;
+  }
+  my $adhoc = val($config,'7024') == '1';
+  if ($adhoc) {
+    # ad-hoc network:
+    my $sec = val($config,'7103');
+    printf "\tWireless mode: Ad-hoc network\n";
+    printf "\tSSID:          %s\n", val($config,'7100');
+    printf "\tChannel:       %s\n", val($config,'7102');
+    printf "\tSecurity:      %s\n", security2string ($sec);
+    if ($sec == 0) {
+      # None => nothing to display
+    } elsif ($sec == 1) {
+      # WEP => Print passphrase
+      printf "\tWEP Key:       %s\n", val($config,'7106');
+    } else {
+      # WPA 1/2 or mixed
+      printf "\tEncryption:    %s\n", encryption2string(val($config,'7118'));
+      printf "\tPassphrase:    %s\n", val($config,'7119');
+    }
+  } else {
+    # infrastructure network
+    my $sec = val($config,'7003');
+    printf "\tSSID:          %s\n", val($config,'7000');
+    printf "\tChannel:       %s\n", val($config,'7002');
+    printf "\tSecurity:      %s\n", security2string ($sec);
+    if ($sec == 0) {
+      # None => nothing to display
+    } elsif ($sec == 1) {
+      # WEP => Print passphrase
+      printf "\tAuthentication:  %s\n", authentication2string(val($config,'7012'));
+      printf "\tWEP Key:       %s\n", val($config,'7006');
+    } else {
+      # WPA 1/2 or mixed
+      printf "\tEncryption:    %s\n", encryption2string(val($config,'7018'));
+      printf "\tPassphrase:    %s\n", val($config,'7019');
+    }
+  }
+  
+  my $dhcp = (val($config,'4020') eq "Enable");
+  printf "\tIPv4 method:   %s\n", $dhcp?"DHCP":"manual";
+  my $associated = val($config,'7014') =~ m/STATE:Associated/;
+  if ($associated || !$dhcp) {
+    printf "\tIP address:    %s\n", val($config,'4000');
+    printf "\tGateway:       %s\n", val($config,'4001');
+    printf "\tNetmask:       %s\n", val($config,'4002');
+  }
+  if ($associated) {
+    my $assinfo = val($config,'7014');
+    printf "\tLink state:    %s\n", $assinfo;
+  } else {
+    # Not connected
+    printf "\tWireless not connected\n";
+  }
+  print "\n\n";
+}
+
+
+sub device_config_request ($) {
+  my $dev = shift;
+  my $cfg = "";
+  debug "Reading current configuration...\n";
+  my $res = bulk_data_write ($dev, "9100:\n", 6);
+  $res = bulk_data_read ($dev, $cfg, 25600);
+  return $cfg;
+}
+
+sub device_config_send ($$) {
+  my $dev = shift;
+  my $cfg = shift;
+  my $tmp = "";
+  progress "Sending new configuation to the device. Please wait";
+  debug "\tNew device config: %s\n", $cfg;
+  my $res = bulk_data_write ($dev, $cfg, length($cfg));
+  sleep_progress (10);
+  # Now reset the device:
+  return device_reset ($dev);
+}
+
+sub config_parse ($) {
+  my $cfg = shift;
+  my @entries = split ('\n', $cfg);
+  my @config = ();
+  foreach (@entries) {
+    my $key = substr ($_, 0, 4);
+    (my $name, my $value) = split (/:/, substr ($_, 5), 2);
+    push (@config, [$key, $name, $value]);
+  }
+  return @config;
+}
+
+# Convert a list of the form [ ["OPTIONID", "OPTIONNAME", VALUE], ...]
+# into a string to be sent to the device
+sub config_create ($) {
+  my $cfg = shift;
+  my $result = "";
+  foreach my $o (@$cfg) {
+    $result .= sprintf ("%s %s:%s\n", $o->[0], $o->[1], $o->[2]);
+  }
+  return $result;
+}
+
+sub set_hostname ($) {
+  my $dev = shift;
+  my $hostname = ask_input ("New hostname: ", \&is_hostname,
+      "\tA hostname can only contain A-Z, a-z, 0-9 and -, and may have 1 to 64 characters\n");;
+  my $config = config_create ([["0001", "BOX_NAME", $hostname]]);
+  debug "\tChanging hostname using config\n\t%s\n", $config;
+  return device_config_send ($dev, $config);
+}
+
+sub device_config_save ($$) {
+  my $filename = shift;
+  my $config = shift;
+  my $status = open FILE, ">$filename";
+  if (!$status) {
+    printf "ERROR: %s\n", $!;
+    return;
+  }
+  print FILE $config;
+  progress "Current print server configuration saved to file '%s'\n", $filename;
+}
+
+sub device_config_restore ($$) {
+  my $dev = shift;
+  my $filename = shift;
+  my $status = open FILE, "<$filename";
+  if (!$status) {
+    printf "ERROR: %s\n", $!;
+    return;
+  }
+  my $config = do { local $/; <FILE> };
+  debug "Configuration file '%s' contains the data:\n", $filename, $config;
+  progress "Loaded configuration data from file '%s', sending it to the device.\n";
+  return device_config_send ($dev, $config);
+}
+
+
+
+
+
+
+###############################################################################
+##  WIRELESS NETWORK DETECTION
+###############################################################################
+
+
+sub parse_survey_data ($) {
+  my $survey = shift;
+  my $networks = {};
+  my @entries = split ("\x0b", $survey);
+  foreach (@entries) {
+    (my $ssid, my $settings) = split ("\x0c", $_);
+    my @settings = split (",", $settings);
+    $networks->{$ssid} = {
+      'mac' => $settings[0],
+      'channel' => $settings[1],
+      'wifi_ver' => $settings[2],
+      'secmode' => $settings[3],
+      'signal' => $settings[4],
+      'adhoc' => $settings[5]
+    };
+  }
+  debug Dumper ($networks);
+  return $networks;
+}
+
+
+sub print_wireless_networks ($) {
+  my $aps = shift;
+  print "Detected wireless networks:\n";
+  my $format = "    %3s %-25s%-9s%-13s%-17s%-8s\n";
+  printf $format, "   ", "SSID", "Signal", "Security", "Type", "channel";
+  print "\t------------------------------------------------------------------------\n";
+  my $i = 0;
+  foreach my $ssid (sort {lc $a cmp lc $b} keys (%$aps)) {
+    ++$i;
+    my $network = $aps->{$ssid};
+    printf $format, $i.")", $ssid, $network->{'signal'}, 
+                    security2string ($network->{'secmode'}),
+                    $network->{'adhoc'}?"Ad-Hoc":"Infrastructure",
+                    $network->{'channel'};
+  }
+  print "\n";
+}
+
+
+
+###############################################################################
+##  INFRASTRUCTURE WIRELESS SETUP (i.e. wlan through access point / router)
+###############################################################################
+
+
+sub wifi_ask_ssid ($) {
+  my $dev = shift;
+  my $aps = scan_for_aps ($dev);
+  print_wireless_networks ($aps);
+  my @ssids = (sort {lc $a cmp lc $b} keys (%$aps));
+  my $newssid;
+  print "Please enter the number or the SSID of the desired wireless network.\n";
+  print "\tEnter '0', 'hidden' or 'h' to connect to a hidden network.\n";
+  print "\tEnter 'r' or 'rescan' to rescan for wireless networks.\n";
+  do {
+    print "Desired wireless network: ";
+    $newssid = input ();
+    return $newssid if (exists $aps->{$newssid});
+    if ($newssid =~ /^[1-9]\d*$/ && ($newssid <= scalar(@ssids))) {
+      return ($aps,$ssids[$newssid-1]);
+    }
+    if ($newssid eq "0" || $newssid eq "h" || $newssid eq "hidden") {
+      $newssid = "";
+      while (length($newssid) < 1) {
+        print "Please enter the SSID: ";
+        $newssid = input ();
+      }
+      return ($aps,$newssid);
+    }
+    if ($newssid eq "r" || $newssid eq "rescan") {
+      return wifi_ask_ssid ($dev);
+    }
+  } while 1; # We'll jump out of the loop via return!
+}
+
+sub wifi_ask_address ($$) {
+  my $ap = shift;
+  my $aps = shift;
+  my $dhcp = ask_choice ("IP-address assignment:", ["DHCP", "Manual"], ["Enable", "Disable"], "Enable");
+  my %result = ("dhcp" => $dhcp);
+  if ($dhcp ne "Enable") {
+    $result{'ip_addr'} = ask_ip_address ("IP-address of the device:\t");
+    $result{'mask'}    = ask_ip_address ("Netmask:\t");
+    $result{'gateway'} = ask_ip_address ("IP-address of the gateway:\t");
+  } else {
+    $result{'ip_addr'} = "0.0.0.0";
+    $result{'mask'}    = "0.0.0.0";
+    $result{'gateway'} = "0.0.0.0";
+  }
+  return %result;
+}
+
+sub wifi_ask_security ($$) {
+  my $ap = shift;
+  my $aps = shift;
+  my %result = ();
+  my $sec = 0;
+  if (defined $aps->{$ap}) {
+    $sec = $aps->{$ap}->{'secmode'};
+    $result{'channel'} = $aps->{$ap}->{'channel'};
+  }
+  $sec = ask_choice ("Security: ", ["None", -1, "WEP", "WPA-PSK", "WPA2-PSK", "WPA/WPA2-PSK"], ['0', '1', '2', '4', '6'], $sec);
+  $result{'secmode'} = $sec;
+
+  if ($sec == 0) {
+    # No encryption, nothing to ask the user
+  } elsif ($sec == 1) {
+    # WEP
+    progress "Using WEP security\n";
+    $result{'authen'} = ask_choice ("Type of authentication:", ["Open System","Shared Key"], ['1','2'], '1');
+    $result{'key'} = ask_wep_key ($ap);
+    $result{'key_len'} = length ($result{'key'})/2;
+  } elsif ($sec == 2 || $sec == 4 || $sec == 6 || $sec == 7) {
+    # WPA1 / WPA2
+    progress "Using %s security\n", security2string($sec);
+    $result{'pskalset'} = ask_choice ("Type of encryption:", ["TKIP", "AES"], ['0','1'], '0');
+    $result{'pskkey'} = ask_input ("Please enter the WPA passphrase for network '$ap': ",
+        \&is_wpa_passphrase, "\tEnter a passprase with 1-63 characters!\n");
+  } else {
+    printf "ERROR: security type %s not supported\n", security2string($sec);
+    return wifi_ask_security ($ap, $aps);
+  }
+  return %result;
+}
+
+sub wifi_config_create ($) {
+  my $newconfig = shift;
+  my $config = [
+    ["4000", "IP_ADDR",   $newconfig->{'ip_addr'}],  # IP-address
+    ["4001", "GATEWAY",   $newconfig->{'gateway'}],
+    ["4002", "MASK   ",   $newconfig->{'mask'}],
+    ["4020", "DHCP_MODE", $newconfig->{'dhcp'}],
+    ["4021", "",          $newconfig->{'dhcp'}], # Unknown, == 4020
+    ["4022", "",          $newconfig->{'dhcp'}], # Unknown, == 4020
+    ["5000", "",          ""], # Unknown, always empty
+    ["5003", "",          ""], # Unknown, always empty
+    ["5101", "",          ""], # Unknown, always empty
+    ["5102", "",          ""], # Unknown, always empty
+    ["5104", "",          ""], # Unknown, always empty
+    ["5103", "",          ""], # Unknown, always empty
+    ["7000", "SSID",      $newconfig->{'SSID'}],
+    ["7001", "DOMAIN",    ""],
+    ["7002", "CHANNEL",   $newconfig->{'channel'}],
+    ["7003", "SECMODE",   $newconfig->{'secmode'}],
+    ["7004", "KEY_LEN",   $newconfig->{'key_len'}],
+    ["7005", "DEFAULTKEY","0"],
+    ["7006", "KEY0",      $newconfig->{'key'}],
+    ["7007", "KEY1",      ""],
+    ["7008", "KEY2",      ""],
+    ["7009", "KEY3",      ""],
+    ["7012", "AUTHEN",    $newconfig->{'authen'}],
+    ["7013", "MODE",      "0"],
+    ["7018", "PSKALSET",  $newconfig->{'pskalset'}],
+    ["7019", "PSKKEY",    $newconfig->{'pskkey'}],
+    ["7024", "STAMODE",   "0"],
+    ["7025", "APCHANNEL", "5"],
+    ["7026", "CHMODE",    "1"],
+    ["7030", "WLMODE",    "0"],
+  ];
+  return config_create ($config);
+}
+
+
+
+###############################################################################
+##  AD-HOC WIRELESS SETUP (i.e. direct connection with print server and PC)
+###############################################################################
+
+
+sub adhoc_send_unknown_command ($) {
+  my $dev = shift;
+  bulk_data_write ($dev, "9971:\n", 6);
+  my $val = "";
+  bulk_data_read ($dev, $val, 1);
+  debug "\tResponse to 9971 Ad-hoc setting command (unknown purpose): %s\n", $val;
+  return $val;
+}
+
+sub adhoc_ask_ssid ($) {
+  my $dev = shift;
+  my $ssid = "";
+  print "\n";
+  do {
+    print "SSID of the ad-hoc wireless connection:";
+    $ssid = input ();
+    if (length ($ssid) > 0) {
+      # scan for wireless networks to check for name clashes
+      my $aps = scan_for_aps ($dev);
+      if (defined ($aps->{$ssid})) {
+        print "\tERROR: wireless network '$ssid' already exists, please choose a different name.\n\n";
+      } else {
+        return $ssid;
+      }
+    }
+  } while 1; # We'll jump out of the loop via return!
+}
+
+sub adhoc_ask_channel ($$) {
+  my $dev = shift;
+  my $ap = shift;
+  my $channel;
+  do {
+    printf "Wireless channel for network '%s' [auto or 0-13]: ", $ap;
+    my $c = input ();
+    if ($c eq "auto") {
+      $channel = "6"; # FIXME
+    } elsif ($c =~ m/^([0-9]|1[0-3])$/ ) {
+      $channel = $c;
+    }
+  } while (!defined ($channel));
+  debug "\tNew channel: %s\n", $channel;
+  return $channel;
+}
+
+sub adhoc_ask_security ($) {
+  my $ssid = shift;
+  my %result = ();
+  my $sec = ask_choice ("Security: ", 
+      ["None", -1, "WEP", "WPA-PSK", "WPA2-PSK", "WPA/WPA2-PSK"], 
+      ['0', '1', '2', '4', '6'], 
+      0);
+  $result{'secmode'} = $sec;
+
+  if ($sec == 0) {
+    # No encryption, nothing to ask the user
+  } elsif ($sec == 1) {
+    # WEP
+    progress "Using WEP security\n";
+    $result{'key'} = ask_wep_key ($ssid);
+    $result{'key_len'} = length ($result{'key'})/2;
+  } elsif ($sec == 2 || $sec == 4 || $sec == 6 || $sec == 7) {
+    # WPA1 / WPA2
+    progress "Using %s security\n", security2string($sec);
+    $result{'pskalset'} = ask_choice ("Type of encryption:", ["TKIP", "AES"], ['0','1'], '0');
+    $result{'pskkey'} = ask_input ("Please enter the WPA passphrase for network '$ssid': ",
+        \&is_wpa_passphrase, "\tEnter a passprase with 1-63 characters!\n");
+  } else {
+    printf "ERROR: security type %s not supported\n", security2string($sec);
+    return adhoc_ask_security ($ssid);
+  }
+  return %result;
+}
+
+sub adhoc_config_create ($) {
+  my $newconfig = shift;
+  my $config = [
+    ["7024", "STAMODE",    "1"],
+    ["7025", "APCHANNEL",  $newconfig->{'channel'}],
+    ["7026", "CHMODE",     "1"], # FIXME: Shall we change this?
+    ["7030", "WLMODE",     "1"], # FIXME: Shall we change this?
+    ["7100", "APSSID",     $newconfig->{'SSID'}],
+    ["7103", "APSECMODE",  $newconfig->{'secmode'}],
+    ["7104", "APKEY_LEN",  $newconfig->{'key_len'}],
+    ["7105", "APDEFAULTKE","0"],
+    ["7106", "APKEY0",     $newconfig->{'key'}],
+    ["7107", "APKEY1",     ""],
+    ["7108", "APKEY2",     ""],
+    ["7109", "APKEY3",     ""],
+    ["7112", "APAUTHEN",   $newconfig->{'authen'}],
+    ["7118", "APPSKALSET", $newconfig->{'pskalset'}],
+    ["7119", "APPSKKEY",   $newconfig->{'pskkey'}]
+  ];
+  return config_create ($config);
+}
+
+
+
+###############################################################################
+##  MAIN OPERATIONS: ASK FOR OPERATION AND HANDLE IT
+###############################################################################
+
+
+sub ask_operation () {
+  return ask_choice (
+    "What do you want to do?", 
+    ["Setup a wireless connection through a wifi router or access point ('infrastructure')",
+     "Setup a direct wireless connection with the printer ('ad-hoc')",
+     -1,
+     "Change the name of the device",
+     -1,
+     "Save the device configuration to a file",
+     "Restore the device configuration from a file",
+     -1,
+     "Reload the configuration",
+     "Exit"
+    ],
+    ["wifi_infrastructure",
+     "wifi_adhoc",
+     "change_hostname",
+     "config_save",
+     "config_restore",
+     "reload",
+     "exit"
+    ],
+    "exit");
+}
+
+sub main () {
+  device_detect ();
+#   my $reconfigured = 0;
+#   my $dev = device_detect () or exit;
+#   device_open ($dev);
+#   my $cfg = device_config_request ($dev);
+#   my @config = config_parse ($cfg);
+#   print_current_configuration (\@config, "Current configuration of the device:\n");
+#   # Ask what to do (set wifi AP, ad-hoc, save, restore)
+#   my $operation = ask_operation ();
+#   debug ("\tSelected operation: %s\n", $operation);
+#   if ($operation eq "wifi_infrastructure") {
+#     # Infrastructure, scan for APs
+#     my ($aps,$newap) = wifi_ask_ssid ($dev);
+#     my %newconfig = ('SSID' => $newap);
+#     debug ("\tSelected wireless network: %s\n", $newap);
+#     my %security = wifi_ask_security ($newap, $aps);
+#     my %ip = wifi_ask_address ($newap, $aps);
+#     %newconfig = (%newconfig, %security, %ip);
+#     my $newcfg = wifi_config_create (\%newconfig);
+#     device_config_send ($dev, $newcfg);
+#     $reconfigured = 1;
+#   } elsif ($operation eq "wifi_adhoc") {
+#     # Ad-hoc connection to print server
+#     my $adhocssid = adhoc_ask_ssid ($dev);
+#     adhoc_send_unknown_command ($dev);
+#     my $channel = adhoc_ask_channel ($dev, $adhocssid);
+#     my %newconfig = ('SSID' => $adhocssid,
+#                      'channel' => $channel,
+#                      adhoc_ask_security ($adhocssid)
+#                     );
+#     my $newcfg = adhoc_config_create (\%newconfig);
+#     device_config_send ($dev, $newcfg);
+#     $reconfigured = 1;
+#   } elsif ($operation eq "change_hostname") {
+#     set_hostname ($dev);
+#     $reconfigured = 1;
+#   } elsif ($operation eq "config_save") {
+#     my $filename = ask_input ("Filename to save to: ", \&is_filename, "");
+#     device_config_save ($filename, $cfg);
+#   } elsif ($operation eq "config_restore") {
+#     my $filename = ask_input ("Filename to load from: ", \&is_filename, "");
+#     device_config_restore ($dev, $filename);
+#   } elsif ($operation eq "reload") {
+#     # do nothing, we'll call main below...
+#   } elsif ($operation eq "exit") {
+#     device_close ($dev);
+#     exit;
+#   } else {
+#     printf "ERROR: unknown operation %s\n", $operation;
+#   }
+#   device_close ($dev);
+#   # if the configuration was changed, print the new config after the device was reset
+#   $dev = device_detect () or exit;
+#   device_open ($dev);
+#   @config = config_parse (device_config_request ($dev));
+#   print_current_configuration (\@config, "New configuration of the device:\n");
+#   
+#   # Loop in main if "reload" is selected...
+#   main () if ($operation eq "reload");
+}
+
+
+
+
+###############################################################################
+##  MAIN FUNCTION
+###############################################################################
+
+main ();