diff --git a/appliance_setup/appliance_setup.py b/appliance_setup/appliance_setup.py index 360dfa05cbfe3b0daa0bc01811d42bd7b0547893..8915d9798e3f88576a1e6e29ce89748025bad3c8 100755 --- a/appliance_setup/appliance_setup.py +++ b/appliance_setup/appliance_setup.py @@ -73,130 +73,20 @@ def ask_device (ui): -""" - -############################################################################### -## 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 scan_for_aps ($) { - my $dev = shift; - progress "Scanning for access points: "; - my $loop = 0; - my $found = 0; - my $survey; - while (!$found && $loop <= 4) { - ++$loop; - debug ("loop=", $loop, "\n"); - my $res = bulk_data_write ($dev, "9107:\n", 6); - $res = bulk_data_read ($dev, my $d="", 0); - sleep_progress (6); - my $cfg = ""; - $res = bulk_data_write ($dev, "9100:\n", 6); - $res = bulk_data_read ($dev, $cfg, 25600); - my @config = config_parse ($cfg); - $survey = val(\@config, '7021'); - $found = (defined ($survey) && length ($survey) > 0); - } - progress "\n"; - if ($found) { - debug "Found wireless networks: \n", $survey; - } else { - print "ERROR: No wireless networks detected.\n"; - } - return parse_survey_data ($survey); -} - -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 { - $newssid = input ("Desired wireless network: "); - 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) { - $newssid = input ("Please enter the SSID: "); - } - 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! -} +def wifi_ask_ssid (ui, dev): + while True: + aps = dev.scan_for_aps () + res = ui.ask_wireless_ap (aps) + print "SSID is {}".format(res) + if res: + return (res, aps) -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; @@ -268,40 +158,28 @@ sub wifi_config_create ($) { 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 { - $ssid = input ("SSID of the ad-hoc wireless connection:"); - if (length ($ssid) > 0) { +def adhoc_ask_ssid (ui, dev): + ssid = "" + ui.progress ("") + while True: + ssid = ui.input ("SSID of the ad-hoc wireless connection:") + if (len(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! -} + aps = dev.scan_for_aps () + if (aps.get(ssid)): + ui.error ("wireless network '%s' already exists, please choose a different name.\n" % ssid) + else: + return ssid +""" def adhoc_ask_channel (ap): channel = False while (!channel): @@ -375,8 +253,8 @@ def ask_operation (ui, dev): def main (): reconfigured = False operation = "" - UI = ConsoleInterface (debug=True) - + UI = ConsoleInterface (debug=False) + dev = ask_device (UI) if (not dev or not dev.device_open ()): return @@ -391,21 +269,23 @@ def main (): UI.debug ("\tSelected operation: %s\n" % operation) if (operation == "wifi_infrastructure"): ## Infrastructure, scan for APs - # TODO - #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); + (newap, aps) = wifi_ask_ssid (UI, dev) + newconfig = {'SSID': newap) + UI.debug ("\tSelected wireless network: %s" % newap) + security = UI.wifi_ask_security ()#TODO: $newap, $aps); + newconfig.update (security) + if (dev.capabilities['ip-address']): + ip = UI.ask_IP_setting () + newconfig.update (ip) + # TODO: #my $newcfg = wifi_config_create (\%newconfig); #device_config_send ($dev, $newcfg); reconfigured = True elif (operation == "wifi_adhoc"): ## Ad-hoc connection to print server # TODO - #my $adhocssid = adhoc_ask_ssid ($dev); - #adhoc_send_unknown_command ($dev); + adhocssid = adhoc_ask_ssid (UI, dev) + dev.command_send ("9971:\n") #my $channel = adhoc_ask_channel ($dev, $adhocssid); #my %newconfig = ('SSID' => $adhocssid, #'channel' => $channel, diff --git a/appliance_setup/configuration.py b/appliance_setup/configuration.py index b118a58ae0dd101192a249d9fd2d35ab6804fea6..6505a995f13e3871d693b3b16d34deebde22dcda 100644 --- a/appliance_setup/configuration.py +++ b/appliance_setup/configuration.py @@ -34,58 +34,57 @@ class Config: self.cfgdata = cfg def print_configuration (self, text): - #print self.cfgstring - ##print self.cfgdata - #print self.val('0012') - res = text + "\tDevice name: %s\n" % self.val('0001') - if (self.val('0012') != "Enable"): - res += "\tTCP/IP not yet configured and/or enabled.\n\n" - return res + res = text + "\tDevice name:\t%s\n" % self.val('0001') adhoc = (self.val('7024') == '1') if adhoc: # ad-hoc network: 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) + res += "\tWireless mode:\tAd-hoc network\n" + res += "\tSSID:\t\t%s\n" % self.val('7100') + res += "\tChannel:\t%s\n" % self.val('7102') + res += "\tSecurity:\t%s\n" % security2string (sec) if (sec == 0): # None => nothing to display pass elif (sec == 1): # WEP => Print passphrase - res += "\tWEP Key: %s\n" % self.val('7106') + res += "\tWEP Key:\t%s\n" % self.val('7106') else: # WPA 1/2 or mixed - res += "\tEncryption: %s\n" % encryption2string(self.val('7118')) - res += "\tPassphrase: %s\n" % self.val('7119') + res += "\tEncryption:\t%s\n" % encryption2string(self.val('7118')) + res += "\tPassphrase:\t%s\n" % self.val('7119') else: # infrastructure network sec = self.val('7003'); - res += "\tSSID: %s\n" % self.val('7000') - res += "\tChannel: %s\n" % self.val('7002') - res += "\tSecurity: %s\n" % security2string (sec) + res += "\tSSID:\t\t%s\n" % self.val('7000') + res += "\tChannel:\t%s\n" % self.val('7002') + res += "\tSecurity:\t%s\n" % security2string (sec) if (sec == 0): # None => nothing to display pass elif (sec == 1): # WEP => Print passphrase - res += "\tAuthentication: %s\n" % authentication2string(self.val('7012')) - res += "\tWEP Key: %s\n" % self.val('7006') + res += "\tAuthentication:\t%s\n" % authentication2string(self.val('7012')) + res += "\tWEP Key:\t%s\n" % self.val('7006') else: # WPA 1/2 or mixed - res += "\tEncryption: %s\n" % encryption2string(self.val('7018')) - res += "\tPassphrase: %s\n" % self.val('7019') + res += "\tEncryption:\t%s\n" % encryption2string(self.val('7018')) + res += "\tPassphrase:\t%s\n" % self.val('7019') - 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') + associated = (self.val('7014').find ("STATE:Associated") >= 0) or \ + (self.val('7014').find ("STATE:Connected") >= 0) + if (self.get ('4000')): + dhcp = (self.val('4020') == "Enable") + res += "\tIPv4 method:\t%s\n" % ("DHCP" if dhcp else "manual") + if (associated or not dhcp): + res += "\tIP address:\t%s\n" % self.val('4000') + res += "\tGateway:\t%s\n" % self.val('4001') + res += "\tNetmask:\t%s\n" % self.val('4002') + else: + res += "\tDevice does not receive an IP address\n" + if associated: - res += "\tLink state: %s\n" % self.val('7014') + res += "\tLink state:\t%s\n" % self.val('7014').replace ("\x0b", "\n\t\t\t").replace (";", "\n\t\t\t") else: # Not connected res += "\tWireless not connected\n" @@ -141,175 +140,14 @@ class Config: - - -############################################################################### -## DEVICE CONFIGURATION HANDLING -############################################################################### - """ - - - - -############################################################################### -## 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 scan_for_aps ($) { - my $dev = shift; - progress "Scanning for access points: "; - my $loop = 0; - my $found = 0; - my $survey; - while (!$found && $loop <= 4) { - ++$loop; - debug ("loop=", $loop, "\n"); - my $res = bulk_data_write ($dev, "9107:\n", 6); - $res = bulk_data_read ($dev, my $d="", 0); - sleep_progress (6); - my $cfg = ""; - $res = bulk_data_write ($dev, "9100:\n", 6); - $res = bulk_data_read ($dev, $cfg, 25600); - my @config = config_parse ($cfg); - $survey = val(\@config, '7021'); - $found = (defined ($survey) && length ($survey) > 0); - } - progress "\n"; - if ($found) { - debug "Found wireless networks: \n", $survey; - } else { - print "ERROR: No wireless networks detected.\n"; - } - return parse_survey_data ($survey); -} - -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 { - $newssid = input ("Desired wireless network: "); - 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) { - $newssid = input ("Please enter the SSID: "); - } - 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 = [ @@ -353,45 +191,6 @@ sub wifi_config_create ($) { ## 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 { - $ssid = input ("SSID of the ad-hoc wireless connection:"); - 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! -} - -def adhoc_ask_channel (ap): - channel = False - while (!channel): - c = input ("Wireless channel for network '%s' [auto or 0-13]: " % ap); - if (c == "auto"): - channel = "6" # FIXME - elif (re.match ('^([0-9]|1[0-3])$', c)): - channel = c - debug ("\tNew channel: %s\n" % channel) - return channel - sub adhoc_config_create ($) { my $newconfig = shift; my $config = [ diff --git a/appliance_setup/device_types.py b/appliance_setup/device_types.py index 162cbf911411eb6bc268636904e3dbd9f110c0fa..91051bdcf9e3e7cfe6d5fc1586a78a0b1293b1ec 100755 --- a/appliance_setup/device_types.py +++ b/appliance_setup/device_types.py @@ -27,7 +27,7 @@ class Device: capabilities = {} def __init__ (self, ui): self.ui = ui - self.capabilities = {'wifi': False, 'ad-hoc': False} + self.capabilities = {'wifi': False, 'ad-hoc': False, 'ip-address': False} def device_string (self): pass @@ -39,32 +39,51 @@ class Device: pass def device_close (self): pass - def command_send (self, cmd): - cfg = "%s:\n" % cmd - res = self.bulk_data_write (cfg, len(cfg)) - return self.bulk_data_read (25600) + def command_send (self, cfg): + res = self.data_write (cfg, len(cfg)) + return self.data_read (25600) def config_retrieve (self): self.ui.debug ("Reading current configuration..."); - return self.command_send ("9100") + return self.command_send ("9100:\n") def config_send (self, config): self.ui.progress ("Sending new configuation to the device. Please wait") cfgstring = config.to_string () self.ui.debug ("\tNew device config: %s\n" % cfgstring) - self.bulk_data_write (cfgstring, len(cfgstring)) + self.data_write (cfgstring, len(cfgstring)) self.ui.sleep_progress (10) # Now reset the device: return self.device_reset () - def bulk_data_write (self, data, length, timeout=500): + def data_write (self, data, length, timeout=500): pass - def bulk_data_read (self, length, timeout=500): + def data_read (self, length, timeout=500): pass def device_reset (self): pass def scan_for_aps (self): - pass + self.ui.progress ("Scanning for access points", False) + loop = 0 + found = False + survey = '' + while (not found and loop <= 4): + loop += 1 + self.ui.debug ("loop=%d\n" % loop) + # trigger a WLAN scan + self.command_send ("9107:\n") + self.ui.sleep_progress (6) + cfg = self.config_retrieve () + config = Config (self.ui, cfgstring=cfg) + survey = config.val('7021') + found = (survey and len(survey) > 0) + self.ui.progress ("") + if found: + self.ui.debug ("Found wireless networks: \n%s" % survey) + else: + self.ui.error ("No wireless networks detected.") + return parse_survey_data (survey) + def print_supported_devices (self): pass def error (self, msg): @@ -111,6 +130,7 @@ class USBDevice (Device): Device.__init__ (self, ui) self.capabilities['wifi'] = True self.capabilities['ad-hoc'] = True + self.capabilities['ip-address'] = True self.dev = dev self.desc = desc self.bus = bus @@ -149,8 +169,8 @@ class USBDevice (Device): def device_reset (self): self.ui.progress ("Resetting the device, please wait") - res = self.command_send ("9002") - self.ui.debug ("\tSent 9002 reset command: %d" % res) + res = self.command_send ("9002:\n") + self.ui.debug ("\tSent 9002 reset command: %s (len: %s)" % (res, len(res))) # Poll the device until it doesn't respond. Then sleep for ~15 seconds try: i=0 @@ -167,7 +187,7 @@ class USBDevice (Device): self.device_close () self.ui.wait_enter ("Device was reset. Please press Return.") - def bulk_data_write (self, data, length, timeout=500): + def data_write (self, data, length, timeout=500): # Add the header (12 bytes): '@\0', packet length, boxname (="XXXXXXXX") request = "@\0" + struct.pack("<H8s", length, self.thisboxname) + data self.ui.debug ("Request: " + request) @@ -179,7 +199,7 @@ class USBDevice (Device): return res # Read and return USB bulk data - def bulk_data_read (self, length, timeout=500): + def data_read (self, length, timeout=500): # TODO: Get rid of the length argument, simply read all that is sent try: res = self.handle.bulkRead (2, length+13, timeout); @@ -225,17 +245,20 @@ import re class Ether8888Packet: ethHeaderFmt = "!6s6sH" headerFmt = "<2s2s2sHH" - localAddr="\0\0\0\0\0\0" - remoteAddr="\xff\xff\xff\xff\xff\xff" + srcAddr="\0\0\0\0\0\0" + dstAddr="\xff\xff\xff\xff\xff\xff" proto = 0x8888 zero = "\0\0" - def __init__ (self, localAddr="\x00\x00\x00\x00\x00\x00", remoteAddr="\xff\xff\xff\xff\xff\xff", proto=0x8888): + status = None + data = None + + def __init__ (self, srcAddr="\x00\x00\x00\x00\x00\x00", dstAddr="\xff\xff\xff\xff\xff\xff", proto=0x8888): self.proto = proto - self.localAddr = localAddr - self.remoteAddr = remoteAddr + self.srcAddr = srcAddr + self.dstAddr = dstAddr def decode (self, data): - self.localAddr, self.remoteAddr, self.proto = struct.unpack(self.ethHeaderFmt,data[:14]) + self.dstAddr, self.srcAddr, self.proto = struct.unpack(self.ethHeaderFmt,data[:14]) if self.proto != 0x8888: # FIXME: Error message about invalid packet return False @@ -244,16 +267,20 @@ class Ether8888Packet: struct.unpack (self.headerFmt, self.ethData[:10]) self.payload = self.ethData[10:self.dataLen+10] + if (self.dataLen>2): + self.status = {"\0\0":True}.get( self.payload[:2]) + if (self.dataLen != len (self.payload)): # FIXME: Error message about invalid packet return False + self.data = self.payload[2:] return True def encode (self, cmd, unknown, nrPackets, dataLen, data): # Ethernet II header (self.cmd, self.unknown, self.nrPackets, self.dataLen,self.payload) = (cmd, unknown, nrPackets, dataLen, data) - d = struct.pack(self.ethHeaderFmt, self.remoteAddr, self.localAddr, self.proto) + d = struct.pack(self.ethHeaderFmt, self.dstAddr, self.srcAddr, self.proto) d += struct.pack (self.headerFmt, self.cmd, self.unknown, self.zero, self.nrPackets, self.dataLen) d += data @@ -261,7 +288,8 @@ class Ether8888Packet: class Ether8888DeviceFactory (DeviceFactory): supported_devices = ( - {'desc':"Vonets VAP11G wireless bridge"}, + {'id': '\x04\xE0\x54\x00', 'desc':"Vonets VAP11G wireless bridge"}, + #{'id': '\x59\x4a\x34\x8c', 'desc':"HP2101nw Wireless USB print server (via WLAN)"}, ); proto=0x8888; def __init__ (self): @@ -282,12 +310,12 @@ class Ether8888DeviceFactory (DeviceFactory): # Create Ethernet II broadcast socket of ethertype 0x8888: sockets = [] - bcAddr = "\xFF\xFF\xFF\xFF\xFF\xFF"; + 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() - packet = Ether8888Packet (localAddr = hwAddr, remoteAddr = bcAddr) + packet = Ether8888Packet (srcAddr = hwAddr, dstAddr = bcAddr) request = packet.encode ("\0\0", "\0\0", 0, 0, "\0"*0x10) # Send and wait for response s.send (request) @@ -300,9 +328,31 @@ class Ether8888DeviceFactory (DeviceFactory): for sock in sread: rxFrame = sock.recv (1500) pack = Ether8888Packet() - if pack.decode (rxFrame) and (not pack.remoteAddr == bcAddr): - ifName,ifProto,pktType,hwType,hwAddr = sock.getsockname() - devices.append (Ether8888Device (ui, ifName, ifProto, pack.localAddr, "Vonets VAP11G wireless bridge")); + # Decode frame and filter out all broadcasts (in case we have a + # loop, e.g. because the device is already connected to the WLAN + # and so all packages sent over eth0 will be received via the wlan + # bridge on the wireless interface!) + if (not pack.decode (rxFrame)): + ui.error ("decoding response packet of device detection") + continue + is_broadcast = (pack.srcAddr == bcAddr) and (pack.dstAddr == bcAddr) + if is_broadcast: + ui.debug ("Received broadcast package instead of response:") + ui.hex_print (rxFrame) + continue + ifName,ifProto,pktType,hwType,hwAddr = sock.getsockname() + devdesc = None + for d in self.supported_devices: + if d['id'] == pack.data[2:6]: + devdesc = d['desc'] + break + else: + ui.hex_print (pack.srcAddr) + ui.progress ("Response received from unknown device (id {}, MAC {}, interface {})".format (formatHex2 (pack.data[2:6]), formatMAC (pack.srcAddr), ifName)) + continue + ui.debug ("Received response packet:") + ui.hex_print (rxFrame) + devices.append (Ether8888Device (ui, ifName, ifProto, pack.srcAddr, devdesc, localAddr = pack.dstAddr)); for s in sockets: s.close (); @@ -325,20 +375,29 @@ class Ether8888Device (Device): proto = 0x8888; desc = "" socket = None - def __init__ (self, ui, iface, proto, mac, desc): + cmds = {'dev_info': "\x00\x00", + 'dev_stat': "\x00\x01", + 'send_data': "\x01\x01", + 'recv_data': "\x02\x01"} + def __init__ (self, ui, iface, proto, mac, desc,localAddr = ""): Device.__init__ (self, ui); self.ifName = iface self.mac = mac self.proto = proto self.desc = desc - self.srcAddr = None - self.destAddr = None + self.localAddr = localAddr + self.remoteAddr = mac self.capabilities['wifi'] = True; self.capabilities['ad-hoc'] = False; + + self.ui.debug("localAddr: ") + self.ui.hex_print (self.localAddr) + self.ui.debug("remoteAddr: ") + self.ui.hex_print (self.remoteAddr) def device_string (self): return "%s (Ethernet interface %s, MAC %12s)" % ( - self.desc, self.ifName, ':'.join('%02x' % ord(b) for b in self.mac)); + self.desc, self.ifName, formatMAC (self.mac)); def device_open (self): try: @@ -350,7 +409,7 @@ class Ether8888Device (Device): 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)) + self.ui.debug ("Successfully opened socket for device '%s' on interface '%s'" % (self.desc, self.ifName)) return True; def device_close (self): @@ -360,69 +419,87 @@ class Ether8888Device (Device): def device_reset (self): self.ui.progress ("Resetting the device, please wait") - res = self.command_send ("9002") - self.ui.debug ("\tSent 9002 reset command: %d" % res) + res = self.command_send ("9002:\n") + self.ui.debug ("\tSent 9002 reset command; response: %s (len: %d)" % (res, len(res))) # Poll the device until it doesn't respond. Then sleep for ~15 seconds self.ui.sleep_progress (20) self.device_close () self.ui.wait_enter ("Device was reset. Please press Return.") - def bulk_data_write (self, data, length, cmd="\x01\x01", unknown="\0\0"): - packet = Ether8888Packet (localAddr = self.localAddr, remoteAddr = self.remoteAddr) - request = packet.encode (cmd, unknown, 0, length, data) - self.ui.debug ("Request: " + request) + + def raw_write (self, data): res = None try: - res = self.socket.send (request) + res = self.socket.send (data) except Exception, e: self.error ("writing data; message: %s" % e.message) return res - # Read and return USB bulk data - def bulk_data_read (self, length, timeout=500): - # TODO: Get rid of the length argument, simply read all that is sent - try: - res = self.handle.bulkRead (2, length+13, timeout); - except Exception, e: - self.error ("reading bulk data; message: %s" % e.message) - return None - - # bulkRead returns a tuple, convert to a binary string - res = ''.join(chr(v) for v in res) - if (len (res) == 0): - self.ui.debug ("\tEmpty response received\n") - return '' + def raw_read (self, length=15000, timeout=500): + self.ui.debug ("raw_read") + toread = 1 # Nr of remaining packets to read + data = None + while (toread>0): + (sread, swrite, sx) = select.select([self.socket], [], [], timeout/1000) + for sock in sread: + rxFrame = sock.recv (length) + toread -= 1 + pack = Ether8888Packet(self.remoteAddr, self.localAddr, self.proto) + if pack.decode (rxFrame): + #self.ui.debug ("Complete returned data frame:") + #self.ui.hex_print (rxFrame) + toread = pack.nrPackets + if (not data): + data = "" + data += pack.data + else: + self.error ("decoding returned data: %s" % rxFrame) + self.ui.debug ("Unable to decode the %d bytes returned: \n" % len (rxFrame)) + self.ui.hex_print (rxFrame) + if (len (sread) == 0 ): + self.error ("reading data, no response received") + toread = 0 + + #self.ui.debug ("Complete returned data:") + #self.ui.hex_print (data) + return data + + def data_write (self, data, length, cmd=None, unknown="\x01\x00"): + self.ui.debug("data_write %d, %s"%(length, data)) + if not cmd: + cmd = self.cmds.get('send_data') + + packet = Ether8888Packet (srcAddr = self.localAddr, dstAddr = self.remoteAddr) + request = packet.encode (cmd, unknown, 0, length, data) + self.ui.debug ("Request: " + request) + res = self.raw_write (request) + time.sleep(1) + return self.raw_read () - self.ui.debug ("read %d bytes: \n" % len (res)) - self.ui.hex_print (res) - # Check and cut off the header after some sanity checks: - if (not res.startswith ("@\0\0")): - self.error ("reading data: Wrong header %s" % res[0:3]) - (datalen,) = struct.unpack ("H", res[3:5]); - realdatalen = len (res)-13 - if (datalen != realdatalen): - self.error ("reading data: Expected %d bytes of data, got %d\n" % (datalen, realdatalen)) - self.boxname = res[5:13] - ## FIXME: Check the name of the box... - ## cut off the header: - return res[13:] + # Read and return USB bulk data + def data_read (self, length, timeout=500): + self.ui.debug("data_read %d"%length) + # TODO: Request return data + packet = Ether8888Packet (srcAddr = self.localAddr, dstAddr = self.remoteAddr) + request = packet.encode (self.cmds.get('recv_data'), "\x02\x00", 0, 0, "") + res = self.raw_write (request) + time.sleep (1) + return self.raw_read (length, timeout) -TODO: - def command_send (self, cmd): - cfg = "%s:\n" % cmd - res = self.bulk_data_write (cfg, len(cfg), cmd="\x01\x01", unknown="\0\0") - return self.bulk_data_read (25600) + def command_send (self, cfg): + res = self.data_write (cfg, len(cfg), cmd=self.cmds.get('send_data'), unknown="\1\0") + return self.data_read (25600) def config_retrieve (self): self.ui.debug ("Reading current configuration..."); - return self.command_send ("9100") + return self.command_send ("9100:\n") def config_send (self, config): self.ui.progress ("Sending new configuation to the device. Please wait") cfgstring = config.to_string () self.ui.debug ("\tNew device config: %s\n" % cfgstring) - self.bulk_data_write (cfgstring, len(cfgstring), cmd="\0x02) + self.command_send (cfgstring) self.ui.sleep_progress (10) # Now reset the device: return self.device_reset () diff --git a/appliance_setup/helpers.py b/appliance_setup/helpers.py index 0e26a92bfdd4b48e92077b5daae7877b70112350..da2038a4eb159137ba1ed79796a31d048de4f845 100755 --- a/appliance_setup/helpers.py +++ b/appliance_setup/helpers.py @@ -47,4 +47,30 @@ def find(f, seq): """Return first item in sequence where f(item) == True.""" for item in seq: if f(item): - return item \ No newline at end of file + return item + +def formatMAC(m): + return ':'.join('%02x' % ord(b) for b in m) + +def formatHex2(d): + return "0x" + " ".join ('%02x' % ord(b) for b in d) + +def parse_survey_data (survey): + networks = {} + entries = filter (None, survey.split ("\x0b")) + for e in entries: + (ssid, settings) = e.split ("\x0c") + settings = settings.split (",") + # If device doesn't support ad-hoc, settings has only 4 entries => add dummy + if len(settings)<6: + settings.append (None) + networks[ssid] = { + 'mac': settings[0], + 'channel': settings[1], + 'wifi_ver':settings[2], + 'secmode': settings[3], + 'signal' : settings[4], + 'adhoc': settings[5] + } + return networks + diff --git a/appliance_setup/user_interface.py b/appliance_setup/user_interface.py index 8a55de1062c2f9f83b520a4d660977d017d9569d..71fce11894bc5ba48dc07f4251a4806b68747d9e 100755 --- a/appliance_setup/user_interface.py +++ b/appliance_setup/user_interface.py @@ -43,8 +43,28 @@ class UserInterface: pass def display_device_settings (self): pass - def print_wireless_networks (self): - pass + # Print a table of available wifi networks + def print_wireless_networks (self, aps): + pass + # Request a wifi network from the user. First, show the table of APs, + # then ask. It's also possible to let the user enter the SSID of a hidden + # network. + def ask_wireless_ap (self, aps): + pass + # Request IP Address settings (DHCP, IP, netmask, gateway); returns a dict + def ask_IP_setting (self): + dhcp = self.ask_choice ("IP-address assignment:", ["DHCP", "Manual"], ["Enable", "Disable"], "Enable"); + result = {"dhcp": dhcp} + if (dhcp == "Enable"); + result['ip_addr'] = self.ask_ip_address ("IP-address of the device:") + result['mask'] = self.ask_ip_address ("Netmask:") + result['gateway'] = self.ask_ip_address ("IP-address of the gateway:") + else: + result['ip_addr'] = "0.0.0.0" + result['mask'] = "0.0.0.0" + result['gateway'] = "0.0.0.0" + return result + def ask_operation (self): pass def ask_ip_address (self, string): @@ -85,12 +105,12 @@ class ConsoleInterface (UserInterface): if (i % 8 == 0): line += " " if (i % 16 == 0): - print ("0x%04x %34s %16s" % (index, line, readable)) + print ("{:#06x} {:<50} {:<16}".format (index, line, readable)) index += 0x10; readable = "" line = "" if (len (line) > 0): - print ("0x%04x %34s %16s" % (index, line, readable)) + print ("{:#06x} {:<50} {:<16}".format (index, line, readable)) sys.stdout.flush() def input (self, str): @@ -150,8 +170,6 @@ class ConsoleInterface (UserInterface): def display_device_settings (self): pass - def print_wireless_networks (self): - pass def ask_operation (self): pass @@ -165,4 +183,60 @@ class ConsoleInterface (UserInterface): "\tInvalid key %s. Length can only be 10 or 26, use only digits 0-9 and letters a-f.\n\n") def wait_enter (self, text): - raw_input (text) \ No newline at end of file + raw_input (text) + + def print_wireless_networks (self, aps): + fmt = " %3s %-25s%-9s%-13s%-17s%-8s\n" + msg = "Detected wireless networks:\n" + msg += fmt % (" ", "SSID", "Signal", "Security", "Type", "channel") + msg += "\t------------------------------------------------------------------------\n" + i = 0 + ssids = aps.keys() + ssids.sort (key=str.lower) + for ssid in ssids: + i += 1 + network = aps.get (ssid, {}) + msg += fmt % (str(i)+")", ssid, network.get ('signal', ''), + security2string (network.get ('secmode', '')), + "Ad-Hoc" if network.get ('adhoc', None) else "Infrastructure", + network.get ('channel', '')) + print msg + + def ask_wireless_ap (self, aps): + self.print_wireless_networks (aps) + ssids = aps.keys() + ssids.sort (key=str.lower) + + print "Please enter the number or the SSID of the desired wireless network." + print "\tEnter '0', 'hidden' or 'h' to connect to a hidden network." + print "\tEnter 'r' or 'rescan' to rescan for wireless networks." + + newssid = None + while (not newssid): + newssid = self.input ("Desired wireless network: ") + print "Newssid=%s" % newssid + if aps.get (newssid): + print "Known SSID %s" % newssid + return newssid + if (newssid == 'h' or newssid == 'hidden' or newssid == '0'): + newssid = '' + while (not newssid): + newssid = self.input ("Please enter the hidden network name:") + return newssid + if (newssid == 'r' or newssid == 'rescan'): + print "Rescan (%s)" % newssid + return None + + try: + i = int(newssid) + print "int %s = %d" % (newssid,i) + if (i>0 and i<len(ssids)): + print "In range" + return ssids[i-1] + else: + print "Not in range" + except Exception, e: + print e.message + return self.ask_wireless_ap (aps) + +