diff --git a/appliance_setup/appliance_setup.py b/appliance_setup/appliance_setup.py index 78e724b8e41ec9841691793859e57d46c494e113..542b957362577ab7986f44a30ec39a031cc87557 100755 --- a/appliance_setup/appliance_setup.py +++ b/appliance_setup/appliance_setup.py @@ -28,143 +28,55 @@ ## support, we'll need a proper kernel module doing the USB port forwarding... import device_types -import user_interface +from user_interface import * import helpers +import configuration #use Data::Dumper; - -our $debug=0; - -our $VERSION=0.01; -print "appliance_setup.py - version $VERSION\n"; -print "Linux configuration utility for the HP 2101nw wireless G USB print server.\n\n"; -print "(C) 2011 Reinhold Kainhofer <reinhold\@kainhofer.com>\n"; -print "License: GPL v2 or later\n\n"; +VERSION=0.01; +#print "appliance_setup.py - version $VERSION"; +#print "Linux configuration utility for the HP 2101nw wireless G USB print server.\n"; +#print "(C) 2011 Reinhold Kainhofer <reinhold\@kainhofer.com>"; +#print "License: GPL v2 or later\n\n"; # The PC always identifies itself as XXXXXXXX. -our $thisboxname = "XXXXXXXX"; +#our $thisboxname = "XXXXXXXX"; +def ask_device (ui): + devices = []; + for f in device_types.device_factories: + devices.extend (f.detect (ui)); -############################################################################### -## USB DEVICE MANAGEMENT / COMMUNICATION FUNCTIONS -############################################################################### + dev = None; + if len(devices) > 1: + devicedescriptions = [d.device_string () for d in devices]; + dev = ui.ask_choice ("Multiple supported devices detected:", devicedescriptions, devices, devices[0]); + elif len(devices) == 1: + dev = devices[0]; + if dev: + ui.progress ("Using device: %s" % dev.device_string ()); + else: + errmsg = ("ERROR: No supported device was found...\n\n" + "Supported devices are:\n"); + devices = []; + for f in device_types.device_factories: + devices.extend (["\t-) %s" % d for d in f.list_supported ()]) + errmsg += "\n".join( devices ) + ui.progress (errmsg) + return dev; -sub device_detect () { - my $usb = Device::USB->new(); - my @devices; - my @devicedescriptions; - foreach (@supported_devices) { - foreach my $dev ($usb->list_devices (@$_)) { - push @devices, $dev; - push @devicedescriptions, sprintf ("%s / ID %04x:%04x (%s: %s)", $dev->filename(), - $dev->idVendor(), $dev->idProduct(), - $dev->manufacturer(), $dev->product()); - } - } - my $dev; - if (scalar (@devices) > 1) { - $dev = ask_choice ("Multiple supported devices detected:", \@devicedescriptions, \@devices, $devices[0]); - } elsif (scalar (@devices) == 1) { - $dev = @devices[0]; - } - if ($dev) { - progress ("Using device: %04x:%04x (%s: %s)\n\n", - $dev->idVendor(), $dev->idProduct(), - $dev->manufacturer(), $dev->product() ); - } else { - progress "\tNo supported devices found\n\n"; - print "ERROR: No supported device was found...\n\n"; - print "Supported devices are (USB IDs): \n"; - foreach (@supported_devices) { - printf "\t%04x:%04x (%s)\n", @$_; - } - print "\n"; - print "Please connect your HP wireless USB print server to \n"; - print "the computer with the black USB cable (micro USB plug) \n"; - print "and run this script again.\n\n"; - } - return $dev; -} - -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; -} +""" +############################################################################### +## USB DEVICE MANAGEMENT / COMMUNICATION FUNCTIONS +############################################################################### -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; @@ -191,80 +103,8 @@ sub device_reset ($) { ############################################################################### -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 ($) { +sub device_config_request ($) { my $dev = shift; my $cfg = ""; debug "Reading current configuration...\n"; @@ -639,67 +479,75 @@ sub ask_operation () { ], "exit"); } +""" -sub main () { - 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"); + +def main (): + reconfigured = False + operation = "" + UI = ConsoleInterface (True) - # Loop in main if "reload" is selected... - main () if ($operation eq "reload"); -} + dev = ask_device (UI) + if (not dev or not dev.device_open ()): + return + + cfg = dev.config_retrieve () + #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... + if (operation == "reload"): + main () +#} diff --git a/appliance_setup/configuration.py b/appliance_setup/configuration.py index ab58c0d388792bcd4931d8c90eb079da4fbcca95..30bd5cfb2e5a7e7926279f48b81ba9451224d020 100644 --- a/appliance_setup/configuration.py +++ b/appliance_setup/configuration.py @@ -8,92 +8,92 @@ class Config: - self.cfgdata = []; - self.cfgdesc = []; + cfgdata = []; + cfgdesc = []; def __init__ (self, ui): self.ui = ui - + def val (self, line): return self.cfgdata.get (line, None) def print_configuration (self): # TODO: ui.progress (text); - ui.print ("\tDevice name: %(0001)s\n" % self.cfgdata); - if (val('0012') != "Enable"): - ui.print "\tTCP/IP not yet configured and/or enabled.\n\n"; + res = "\tDevice name: %(0001)s\n" % self.cfgdata; + if (self.val('0012') != "Enable"): + res += "\tTCP/IP not yet configured and/or enabled.\n\n" return - adhoc = (val('7024') == '1'); + adhoc = (self.val('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) { + sec = self.val('7103'); + res += "\tWireless mode: Ad-hoc network\n" + res += "\tSSID: %s\n" % self.val('7100') + res += "\tChannel: %s\n" % self.val('7102') + res += "\tSecurity: %s\n" % security2string (sec) + if (sec == 0): # None => nothing to display - } elsif ($sec == 1) { + pass + elif (sec == 1): # WEP => Print passphrase - printf "\tWEP Key: %s\n", val($config,'7106'); - } else { + res += "\tWEP Key: %s\n" % self.val('7106') + else: # WPA 1/2 or mixed - printf "\tEncryption: %s\n", encryption2string(val($config,'7118')); - printf "\tPassphrase: %s\n", val($config,'7119'); - } - } else { + res += "\tEncryption: %s\n" % encryption2string(self.val('7118')) + res += "\tPassphrase: %s\n" % self.val('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) { + sec = self.val('7003'); + res += "\tSSID: %s\n", self.val('7000') + res += "\tChannel: %s\n", self.val('7002') + res += "\tSecurity: %s\n", security2string (sec) + if (sec == 0): # None => nothing to display - } elsif ($sec == 1) { + pass + elif (sec == 1): # WEP => Print passphrase - printf "\tAuthentication: %s\n", authentication2string(val($config,'7012')); - printf "\tWEP Key: %s\n", val($config,'7006'); - } else { + res += "\tAuthentication: %s\n" % authentication2string(self.val('7012')) + res += "\tWEP Key: %s\n" % self.val('7006') + else: # WPA 1/2 or mixed - printf "\tEncryption: %s\n", encryption2string(val($config,'7018')); - printf "\tPassphrase: %s\n", val($config,'7019'); - } - } + res += "\tEncryption: %s\n" % encryption2string(self.val('7018')) + res += "\tPassphrase: %s\n" % self.val('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 { + dhcp = (self.val('4020') == "Enable") + res += "\tIPv4 method: %s\n" % ("DHCP" if dhcp else "manual") + associated = (self.val('7014').find ("STATE:Associated") >= 0) + if (associated or not dhcp): + res += "\tIP address: %s\n" % self.val('4000') + res += "\tGateway: %s\n" % self.val('4001') + res += "\tNetmask: %s\n" % self.val('4002') + if associated: + res += "\tLink state: %s\n" % self.val('7014') + else: # Not connected - printf "\tWireless not connected\n"; - } - print "\n\n"; - - pass + res += "\tWireless not connected\n" + res += "\n\n" + return res + + def config_parse (self, data): + entries = data.split ('\n'); + self.cfgdata = []; + self.cfgdesc = []; + entry_re = re.compile ("^([0-9]{4}) ([A-Z]+):(.*)$"); + for l in entries: + m = entry_re.match (l) + (line, name, value) = m.group (1, 2, 3) + self.cfgdata[line] = value + self.cfgdesc[line] = name + print self.cfgdata + print self.cfgdesc ############################################################################### ## DEVICE CONFIGURATION HANDLING ############################################################################### - +""" 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], ...] @@ -508,3 +508,4 @@ sub main () { ############################################################################### main (); +""" \ No newline at end of file diff --git a/appliance_setup/device_types.py b/appliance_setup/device_types.py index 2d443560682a5e9c592a51c33086c1ab5fb0f2e7..0c5bd2c3d16a8e79702837db0110b22daac1b491 100755 --- a/appliance_setup/device_types.py +++ b/appliance_setup/device_types.py @@ -8,10 +8,25 @@ import usb -## Base class -class DeviceType: +device_factories = []; + +class DeviceFactory: def __init__ (self): pass + def list_supported (self): + return []; + def detect (self, ui): + return []; + +## Base class +class Device: + ui = None + capabilities = {'wifi': False, 'ad-hoc': False} + def __init__ (self, ui): + self.ui = ui + + def device_string (self): + pass def detect_devices (self): pass @@ -30,76 +45,254 @@ class DeviceType: pass def print_supported_devices (self): pass + def error (self, msg): + self.ui.error (msg) + +class USBDeviceFactory (DeviceFactory): + supported_devices = ( + {'vendor_id':0x03f0, 'product_id':0xcd02, 'desc':"HP 2101nw wireless G USB print server"}, + ); + def __init__ (self): + DeviceFactory.__init__ (self) + pass + def list_supported (self): + devices = []; + for d in self.supported_devices: + devices.append ("%(desc)s, USB %(vendor_id)04x:%(product_id)04x" % d); + return devices; + + def detect (self, ui): + devices = []; + for d in self.supported_devices: + for bus in usb.busses(): + for dev in bus.devices: + if (dev.idVendor == d['vendor_id'] and dev.idProduct == d['product_id']): + devices.append (USBDevice (ui, dev, bus.dirname, d['desc'])); + return devices; + +device_factories.append (USBDeviceFactory()); ## USB-based devices like the HP2101nw -class USBDevice (DeviceType): +class USBDevice (Device): + dev = None + desc = "Unknown" + bus = "" + handle = None + thisboxname = "XXXXXXXX" + def __init__ (self, ui, dev, bus, desc): + Device.__init__ (self, ui) + self.dev = dev + self.desc = desc + self.bus = bus + + def device_string (self): + return "%s (USB device %04x:%04x, Bus %s Device %s)" % ( + self.desc, self.dev.idVendor, self.dev.idProduct, + self.bus, self.dev.filename); + + def device_open (self): + # TODO: Use exceptions rather than those nasty if (res<0) checks + self.handle = self.dev.open () + if (self.handle < 0): + self.error ("opening device (%d): %s" % res) + self.device_close () + return False + try: #Linux will ALWAYS fail here! + res = self.handle.detachKernelDriver (0) + except usb.USBError: + pass + + try: + self.handle.setConfiguration(1) + self.handle.claimInterface(0); + except Exception, e: + self.error ("setting configuration 1 and claiming interface 0 (%d): %s\n" % (1, e.message)); + self.device_close () + return False + return self.handle; + + def device_close (self): + self.handle.releaseInterface(0) + self.handle.reset () + self.handle = None + + def config_retrieve (self): + self.ui.debug ("Reading current configuration...\n"); + cfg = "" + res = self.bulk_data_write ("9100:\n", 6) + #res = bulk_data_read ($cfg, 25600); + #return $cfg; + + + def bulk_data_write (self, data, length): + # Add the header (12 bytes): '@\0', packet length, boxname (="XXXXXXXX") + request = "@\0" + struct.pack("<H8s", length, self.thisboxname) + data + self.ui.debug ("Request: " + request) + res = None + try: + res = self.handle.bulkWrite (1, request, 500) + except Exception, e: + self.error ("writing bulk data; message: %s" % e.message) + return res + +# Read USB bulk data into the second argument (output argument!), return +# size of data + def bulk_data_read ($$$): + # 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 = ""; + res = self.handle.bulkRead (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; + + + + +import select +import socket +import struct +import subprocess +import re + +class Ether8888Packet: + def __init__ (self): + pass + def decode (self, data): + self.dstAddr, self.srcAddr, self.proto = struct.unpack("!6s6sH",data[:14]) + if self.proto != 0x8888: + # FIXME: Error message about invalid packet + return False + self.ethData = data[14:] + self.cmd,self.unknown,self.zero,self.nrPackets,self.dataLen = \ + struct.unpack ("<2s2s2sHH", self.ethData[:10]) + self.payload = self.ethData[10:self.dataLen+10] + + if (self.dataLen != len (self.payload)): + # FIXME: Error message about invalid packet + return False + return True + +class Ether8888DeviceFactory (DeviceFactory): supported_devices = ( - {'vendor_id':0x03f0, 'product_id':0xcd02, 'desc':"HP 2101nw wireless G USB print server"} + {'desc':"Vonets VAP11G wireless bridge"}, ); - dev = None; + proto=0x8888; def __init__ (self): - DeviceType.__init__ () - - def detect_devices (): - devices = (); + DeviceFactory.__init__ (self) + pass + def list_supported (self): + devices = []; for d in self.supported_devices: - for dev in (usb.list_devices (d['vendor_id'], d['product_id'])): - devices.append (dev); - devicedescriptions.append ("%s / ID %04x:%04x (%s: %s)" % (dev.filename(), - dev.idVendor(), dev.idProduct(), - dev.manufacturer(), dev.product()); - - if len(devices) > 1: - dev = ask_choice ("Multiple supported devices detected:", devicedescriptions, devices, devices[0]); - else: - def = devices[0]; - - if dev: - progress ("Using device: %04x:%04x (%s: %s)\n\n", - dev.idVendor(), dev.idProduct(), - dev.manufacturer(), dev.product() ); - else: - progress "\tNo supported devices found\n\n"; - print "ERROR: No supported device was found...\n\n"; - print "Supported devices are (USB IDs): \n"; - for d in (self.supported_devices): - print "\t%(vendor_id)04x:%(product_id)04x (%(desc)s)\n" % d; - print "\n"; - print "Please connect your HP wireless USB print server to \n"; - print "the computer with the black USB cable (micro USB plug) \n"; - print "and run this script again.\n\n"; - return dev; - - def device_open () { - res = self.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; -} + devices.append ("%(desc)s, Ethernet, type 0x%(proto)04x" % dict({'proto': self.proto}, **d)); + return devices; + def detect (self, ui): + devices = []; + try: + ifconfig = subprocess.check_output ("ifconfig") + if_re = re.compile ("([a-zA-Z0-9]+)\s+Link") + interfaces = [i for i in if_re.findall (ifconfig) if (not i == "lo")]; + + # Create Ethernet II broadcast socket of ethertype 0x8888: + sockets = [] + bcAddr = "\xFF\xFF\xFF\xFF\xFF\xFF"; + for i in interfaces: + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, self.proto) + s.bind((i,self.proto)) + ifName,ifProto,pktType,hwType,hwAddr = s.getsockname() + txFrame = struct.pack("!6s6sH",bcAddr,hwAddr,self.proto) + "\x00"*0x10 + # Send and wait for response + s.send (txFrame) + sockets.append (s) + + found = True + while found: + (sread, swrite, sx) = select.select(sockets, [], [], 0.5) + found = len (sread) > 0; + for sock in sread: + rxFrame = sock.recv (1500) + pack = Ether8888Packet() + if pack.decode (rxFrame) and (not pack.dstAddr == bcAddr): + ifName,ifProto,pktType,hwType,hwAddr = sock.getsockname() + devices.append (Ether8888Device (ui, ifName, ifProto, pack.srcAddr, "Vonets VAP11G wireless bridge")); + for s in sockets: + s.close (); + + except socket.error, e: + ui.progress ("") + ui.progress ("WARNING: Not running with root privileges, the following devices will NOT be found:") + for i in self.list_supported (): + ui.progress ("\t-) %s" % i) + ui.progress ("") + pass + return devices; + +device_factories.append (Ether8888DeviceFactory()); ## ethernet devices (using ethernet II proto 0x8888), like the VAP11G -class Ether8888Device (DeviceType): - def __init__ (self): - DeviceType.__init__ (); +class Ether8888Device (Device): + ifName = "" + destAddr = "" + srcAddr = "" + proto = 0x8888; + desc = "" + socket = None + def __init__ (self, ui, iface, proto, mac, desc): + Device.__init__ (self, ui); + self.ifName = iface + self.mac = mac + self.proto = proto + self.desc = desc + self.srcAddr = None + self.destAddr = None -## FTP-based devices like ??? -class FTPDevice (DeviceType): - def __init__ (self): - DeviceType.__init__ (); + def device_string (self): + return "%s (Ethernet interface %s, MAC %12s)" % ( + self.desc, self.ifName, ':'.join('%02x' % ord(b) for b in self.mac)); + + def device_open (self): + try: + s = socket.socket (socket.AF_PACKET, socket.SOCK_RAW, self.proto) + s.bind ((self.ifName,self.proto)) + ifName,ifProto,pktType,hwType,hwAddr = s.getsockname() + self.socket = s + except socket.error, e: + self.error ("Error opening socket for device '%s' on interface '%s'; message: %s" % (self.desc, self.ifName, e.message)) + s.close () + return False + self.ui.progress ("Successfully opened socket for device '%s' on interface '%s'" % (self.desc, self.ifName)) + return True; + + def device_close (self): + if self.socket: + self.socket.close () + self.socket = None + + +### FTP-based devices like ??? +#class FTPDevice (Device): +# def __init__ (self): +# Device.__init__ (self); diff --git a/appliance_setup/helpers.py b/appliance_setup/helpers.py index 222811432f33aea5a316f02f0711ec15145673d5..ad1f09be29e54fa6223d20e63122cdee89124f8a 100755 --- a/appliance_setup/helpers.py +++ b/appliance_setup/helpers.py @@ -15,13 +15,13 @@ def is_ip_address (ip): def security2string (sec): return { - 0 => "None", - 1 => "WEP", - 2 => "WPA-PSK", - 4 => "WPA2-PSK", # WPA2-PSK TKIP - 6 => "WPA/WPA2-PSK", # WPA/WPA2 and WPA2-PSK CCMP - 7 => "WPA-EAP", - 8 => "WPA2-EAP" + 0: "None", + 1: "WEP", + 2: "WPA-PSK", + 4: "WPA2-PSK", # WPA2-PSK TKIP + 6: "WPA/WPA2-PSK", # WPA/WPA2 and WPA2-PSK CCMP + 7: "WPA-EAP", + 8: "WPA2-EAP" }.get (sec, "Unknown (%d)" % sec) def encryption2string (enc): @@ -31,10 +31,10 @@ def authentication2string (auth): return {1: "Open System", 2: "Shared Key"}.get (auth, "Unknown (%d)" % auth) def is_wep_key (key): - return (re.match("[0-9a-fA-F]{10}$", key) || re.match('[0-9a-fA-F]{26}$', key)) + return (re.match("[0-9a-fA-F]{10}$", key) or re.match('[0-9a-fA-F]{26}$', key)) def is_wpa_passphrase (passphrase): - return (0 < len (passphrase) && len (passphrase) < 64) + return (0 < len (passphrase) and len (passphrase) < 64) def is_filename (fn): return (len(fn)>0) diff --git a/appliance_setup/user_interface.py b/appliance_setup/user_interface.py index 52d397867fae131460adf6c82f2741788035fa89..817bedd49721a42be0a3addbe82b7788770d291c 100755 --- a/appliance_setup/user_interface.py +++ b/appliance_setup/user_interface.py @@ -7,110 +7,145 @@ ## (C) 2011 Reinhold Kainhofer <reinhold@kainhofer.com> ## License: GPL v2 or later +import re; + class UserInterface: - def __init__ (self, debug): - self.debug = debug; - def progress (self, str): - pass - def debug (self, str): - pass - def input (self, str): - pass - ## Sleep for dur seconds, show some kind of progress bar / dots - def sleep_progress (self, dur): - pass - ## 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 - def ask_choice (self, text, options, values, default): - pass - # 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. - def ask_input (self, text, validator, message): - pass - def display_device_settings (self): - pass - def print_wireless_networks (self): - pass - def ask_operation (self): - pass - def ask_ip_address (self, string): - pass - def ask_wep_key (self, ap): - pass + is_debug = False + def __init__ (self, debug): + self.is_debug = debug; + def progress (self, str): + pass + def debug (self, str): + pass + def error (self, str): + pass + def input (self, str): + pass + ## Sleep for dur seconds, show some kind of progress bar / dots + def sleep_progress (self, dur): + pass + ## 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 + def ask_choice (self, text, options, values, default): + pass + # 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. + def ask_input (self, text, validator, message): + pass + def display_device_settings (self): + pass + def print_wireless_networks (self): + pass + def ask_operation (self): + pass + def ask_ip_address (self, string): + pass + def ask_wep_key (self, ap): + pass + def hex_print (self, data): + pass class ConsoleInterface (UserInterface): - def __init__ (self, debug): - UserInterface.__init__ (debug); - def progress (self, str): + def __init__ (self, debug): + UserInterface.__init__ (self, debug); + def progress (self, str): + print str; + def debug (self, str): + if (self.debug): print str; - def debug (self, str): - if (self.debug): - print str; - def input (self, str): - s = raw_input (str).strip (); - return s + def error (self, str): + print "ERROR " + str; + def hex_print (self, data): + i = 0; + readable="" + line = "" + for c in data: + line += ("%02x " % ord(c)) + readable += c; + i += 1 + if (i % 8 == 0): + line += " " + if (i == 16): + line += (" %s" % readable) + print (line) + i = 0 + readable = "" + line = "" + line += (" %s" % readable) + print (line) + + def input (self, str): + s = raw_input (str).strip (); + return s - def sleep_progress (self, dur): - for i in range(dur): - progress "." - sleep (1); - progress "\n" + def sleep_progress (self, dur): + for i in range(dur): + progress (".") + sleep (1) + progress ("\n") - def ask_choice (self, text, options, values, default): - print "%s\n" % text - i = 1 - defindex = 1 - for o in options: - if (o == -1): - print "\t---\n" - else: - print "\t%d) %s\n" % (i, o) - if (values[i-1] == default): - defindex = i - i += 1 - while (retval == undefined): - op = self.input ("Your choice (default: %d): " % i); - if (op == ""): - retval = default; - elif (re.match ('[1-9][0-9]*$', op) && ($op <= len (values))): - retval = values.get (op-1); - else: - print "\tInvalid input. Please enter a number from 1 to %d, or simply press Return to use the default.\n" % len(values); - return retval; + def ask_choice (self, text, options, values, default): + print text + i = 1 + defindex = 1 + for o in options: + if (o == -1): + print "\t---" + else: + print "\t%d) %s" % (i, o) + if (values[i-1] == default): + defindex = i + i += 1 + print ("") + retval = None + while (retval == None): + op = self.input ("Your choice (default: %d): " % defindex); + index = None; + try: + index = int (op); + except ValueError: + pass + if (op == ""): + retval = default; + elif (index != None and index <= len (values)): + retval = values[index-1]; + else: + print "\tInvalid input. Please enter a number from 1 to %d, or simply press Return to use the default." % len(values); + 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. - def ask_input (self, text, validator, message): - retval = "" - valid = False - while (!valid): - retval = self.input (text) - valid = validator (retval) - if (!valid): - print message % 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. + def ask_input (self, text, validator, message): + retval = "" + valid = False + while (not valid): + retval = self.input (text) + valid = validator (retval) + if (not valid): + print message % retval + return retval - def display_device_settings (self): - pass - def print_wireless_networks (self): - pass - def ask_operation (self): - pass + def display_device_settings (self): + pass + def print_wireless_networks (self): + pass + def ask_operation (self): + pass - def ask_ip_address (self, string): - return self.ask_input (string, self.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") + def ask_ip_address (self, string): + return self.ask_input (string, self.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") - def ask_wep_key (self, ap): - return self.ask_input ( - "Please enter the WEP key (10 or 26 characters, 0-9 and a-f) for network '%s': " % ap, - helpers.is_wep_key, - "\tInvalid key %s. Length can only be 10 or 26, use only digits 0-9 and letters a-f.\n\n") + def ask_wep_key (self, ap): + return self.ask_input ( + "Please enter the WEP key (10 or 26 characters, 0-9 and a-f) for network '%s': " % ap, + helpers.is_wep_key, + "\tInvalid key %s. Length can only be 10 or 26, use only digits 0-9 and letters a-f.\n\n")