From 0846262df5150042d38accad44bb805cbc4945b6 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Thu, 15 Sep 2005 03:29:57 +0000 Subject: fallback to wpa_cli or iwlist/iwconfig when needed (#18516) --- perl-install/detect_devices.pm | 4 +- perl-install/network/monitor.pm | 78 ++++++++++++++------ perl-install/standalone/drakroam | 142 +++++++++++++++++++++++++++---------- perl-install/standalone/net_applet | 29 ++++---- 4 files changed, 176 insertions(+), 77 deletions(-) diff --git a/perl-install/detect_devices.pm b/perl-install/detect_devices.pm index 34bddb75d..5d00955d1 100644 --- a/perl-install/detect_devices.pm +++ b/perl-install/detect_devices.pm @@ -587,7 +587,7 @@ sub is_wireless_interface { #- i.e interfaces for which get_wireless_stats() is available c::isNetDeviceWirelessAware($interface) || -e "/sys/class/net/$interface/wireless"; } -sub has_wireless() { any { is_wireless_interface($_) } getNet() } +sub get_wireless_interface() { find { is_wireless_interface($_) } getNet() } sub is_bridge_interface { my ($interface) = @_; @@ -951,7 +951,7 @@ sub matching_type { if ($type =~ /laptop/i) { return isLaptop(); } elsif ($type =~ /wireless/i) { - return has_wireless(); + return to_bool(get_wireless_interface()); } } diff --git a/perl-install/network/monitor.pm b/perl-install/network/monitor.pm index 38912af97..93384237b 100644 --- a/perl-install/network/monitor.pm +++ b/perl-install/network/monitor.pm @@ -15,36 +15,68 @@ sub new { } sub list_wireless { - my ($o) = @_; - my $results; - eval { $results = $o->call_method('ScanResults') }; - my %networks; - #- bssid / frequency / signal level / flags / ssid - while ($results =~ /^((?:[0-9a-f]{2}:){5}[0-9a-f]{2})\t(\d+)\t(\d+)\t(.*?)\t(.*)$/mg) { - # wpa_supplicant may list the network two times, use ||= - $networks{$1}{frequency} ||= $2; - $networks{$1}{signal_level} ||= $3; - $networks{$1}{flags} ||= $4; - $networks{$1}{ssid} ||= $5 if $5 ne ''; - $networks{$1}{approx_level} ||= 20 + min(80, int($3/20)*20); + my ($monitor, $o_intf) = @_; + my ($results, $list, %networks); + #- first try to use mandi + eval { + $results = $monitor->call_method('ScanResults'); + $list = $monitor->call_method('ListNetworks'); + }; + my $has_roaming = defined $results && defined $list; + #- try wpa_cli if we're root + if ($@ && !$>) { + $results = run_program::get_stdout('/usr/sbin/wpa_cli', '2>', '/dev/null', 'scan_results'); + $list = run_program::get_stdout('/usr/sbin/wpa_cli', '2>', '/dev/null', 'list_networks'); } - my $list; - eval { $list = $o->call_method('ListNetworks') }; - #- network id / ssid / bssid / flags - while ($list =~ /^(\d+)\t(.*?)\t(.*?)\t(.*)$/mg) { - if (my $net = $networks{$3} || find { $_->{ssid} eq $2 } values(%networks)) { - $net->{id} = $1; - $net->{ssid} ||= $2; - $net->{current} = to_bool($4 eq '[CURRENT]'); + if (defined $results && defined $list) { + #- bssid / frequency / signal level / flags / ssid + while ($results =~ /^((?:[0-9a-f]{2}:){5}[0-9a-f]{2})\t(\d+)\t(\d+)\t(.*?)\t(.*)$/mg) { + # wpa_supplicant may list the network two times, use ||= + $networks{$1}{frequency} ||= $2; + $networks{$1}{signal_level} ||= $3; + $networks{$1}{flags} ||= $4; + $networks{$1}{essid} ||= $5 if $5 ne ''; } + #- network id / ssid / bssid / flags + while ($list =~ /^(\d+)\t(.*?)\t(.*?)\t(.*)$/mg) { + if (my $net = $networks{$3} || find { $_->{essid} eq $2 } values(%networks)) { + $net->{id} = $1; + $net->{essid} ||= $2; + $net->{current} = to_bool($4 eq '[CURRENT]'); + } + } + } elsif ($o_intf) { + #- else use iwlist + my $current_essid = chomp_(run_program::get_stdout('/sbin/iwgetid', '-r', $o_intf)); + my $current_ap = lc(chomp_(run_program::get_stdout('/sbin/iwgetid', '-r', '-a', $o_intf))); + my @list = run_program::get_stdout('/sbin/iwlist', $o_intf, 'scanning'); + my $net = {}; + foreach (@list) { + if ((/^\s*$/ || /Cell/) && exists $net->{ap}) { + $net->{current} = to_bool($net->{essid} eq $current_essid || $net->{ap} eq $current_ap); + $networks{$net->{ap}} = $net; + $net = {}; + } + /Address: (.*)/ and $net->{ap} = lc($1); + /ESSID:"(.*?)"/ and $net->{essid} = $1; + /Mode:(\S*)/ and $net->{mode} = $1; + if (m!Quality[:=](\S*)/!) { + my $qual = $1; + $net->{signal_level} = $qual =~ m!/! ? eval($qual)*100 : $qual; + } + /Extra:wpa_ie=/ and $net->{flags} = '[WPA]'; + /key:(\S*)\s/ and $net->{flags} ||= $1 eq 'on' && '[WEP]'; + } } - \%networks; + + $networks{$_}{approx_level} = 20 + min(80, int($networks{$_}{signal_level}/20)*20) foreach keys %networks; + (\%networks, $has_roaming); } sub select_network { my ($o, $id) = @_; - $networks = $o->call_method('SelectNetwork', - Net::DBus::Binding::Value->new(&Net::DBus::Binding::Message::TYPE_UINT32, $id)); + $o->call_method('SelectNetwork', + Net::DBus::Binding::Value->new(&Net::DBus::Binding::Message::TYPE_UINT32, $id)); } 1; diff --git a/perl-install/standalone/drakroam b/perl-install/standalone/drakroam index e5fe256e4..5294cfbd4 100755 --- a/perl-install/standalone/drakroam +++ b/perl-install/standalone/drakroam @@ -16,14 +16,18 @@ use interactive; use mygtk2; use ugtk2 qw(:create :helpers :wrappers); use Gtk2::SimpleList; +use network::ethernet; use network::monitor; -use network::wireless; use network::network; -use network::ethernet; +use network::tools; +use network::wireless; my $in = 'interactive'->vnew('su'); -my $wireless_device = find { detect_devices::is_wireless_interface($_) } detect_devices::getNet(); +my $arg_ap; +/^--ap=(.*)/ and $arg_ap = $1 foreach @ARGV; + +my $wireless_device = detect_devices::get_wireless_interface(); unless ($wireless_device) { ugtk2::err_dialog(N("Error"), N("You do not have any wireless interface. @@ -44,13 +48,15 @@ my $wireless_list = Gtk2::SimpleList->new( N("SSID") => "text", '' => "pixbuf", N("Encryption") => "text", - N("Signal strength") => "pixbuf" + N("Operating Mode") => "text", + N("Signal strength") => "pixbuf", ); $wireless_list->get_selection->set_mode('single'); my $dbus = dbus_object::system_bus(); my $monitor = network::monitor->new($dbus); my $wireless_networks = {}; +my $has_roaming; my %pixbufs = ( @@ -62,35 +68,34 @@ my %pixbufs = ); sub update_networks() { - $wireless_networks = $monitor->list_wireless; + ($wireless_networks, $has_roaming) = network::monitor::list_wireless($monitor, $wireless_device); @{$wireless_list->{data}} = (); while (my ($ap, $network) = each(%$wireless_networks)) { push @{$wireless_list->{data}}, [ $ap, $network->{current} ? $pixbufs{state}{connected} : undef, - $network->{ssid} || $ap, + $network->{essid} || $ap, $network->{flags} ? $pixbufs{keyring} : undef, $network->{flags}, - $pixbufs{link_level}{$network->{approx_level}} + $network->{mode}, + $pixbufs{link_level}{$network->{approx_level}}, ]; } 1; } -sub configure_selected() { - my ($selected) = $wireless_list->get_selected_indices or return; - my $ap = $wireless_list->{data}[$selected][0]; +sub configure_ap { + my ($ap) = @_; my $network = $wireless_networks->{$ap}; - - my $ssid = $network->{ssid}; + my $essid = $network->{essid}; my $wireless_net = - $ssid && exists $net->{wireless}{$ssid} ? - $net->{wireless}{$ssid} : + $essid && exists $net->{wireless}{$essid} ? + $net->{wireless}{$essid} : exists $net->{wireless}{$ap} ? $net->{wireless}{$ap} : {}; - $wireless_net->{WIRELESS_ESSID} = $ssid if $ssid; + $wireless_net->{WIRELESS_ESSID} = $essid if $essid; my ($wireless_enc_mode, $wireless_enc_key, $wireless_restricted); ($wireless_enc_key, $wireless_restricted) = network::wireless::get_wep_key_from_iwconfig($wireless_net->{WIRELESS_ENC_KEY}); @@ -101,10 +106,10 @@ sub configure_selected() { $in->ask_from_({ title => "Wireless settings", - messages => N("Please enter settings for wireless network \"%s\"", $ssid || $ap) + messages => N("Please enter settings for wireless network \"%s\"", $essid || $ap) }, [ - { label => N("Network name (ESSID)"), val => \$wireless_net->{WIRELESS_ESSID}, disabled => sub { $ssid } }, + { label => N("Network name (ESSID)"), val => \$wireless_net->{WIRELESS_ESSID}, disabled => sub { $essid } }, { label => N("Encryption mode"), val => \$wireless_enc_mode, list => [ keys %network::wireless::wireless_enc_modes ], sort => 1, @@ -118,40 +123,96 @@ sub configure_selected() { ) or return; $wireless_net->{BOOTPROTO} = $dhcp ? 'dhcp' : 'static'; - $wireless_net->{WIRELESS_ENC_KEY} = network::wireless::convert_wep_key_for_iwconfig($wireless_enc_key, $wireless_enc_mode eq 'restricted'); - $wireless_net->{WIRELESS_WPA_DRIVER} = network::wireless::wpa_supplicant_get_driver($wireless_module); + $wireless_net->{WIRELESS_ENC_KEY} = $wireless_enc_key && network::wireless::convert_wep_key_for_iwconfig($wireless_enc_key, $wireless_enc_mode eq 'restricted'); + $wireless_net->{WIRELESS_MODE} = $network->{mode} eq 'Master' ? 'Managed' : $network->{mode}; - my $wireless_file = "/etc/sysconfig/network-scripts/wireless.d/" . ($ssid || $ap); + if ($has_roaming || $wireless_enc_mode eq 'wpa-psk') { + $wireless_net->{WIRELESS_WPA_DRIVER} = network::wireless::wpa_supplicant_get_driver($wireless_module); + network::wireless::wpa_supplicant_add_network($wireless_net->{WIRELESS_ESSID}, $wireless_enc_mode, $wireless_enc_key); + } else { + delete $wireless_net->{WIRELESS_WPA_DRIVER}; + } + + my $ssid = $essid || $ap; + $net->{wireless}{$ssid} = $wireless_net; + + my $wireless_file = "/etc/sysconfig/network-scripts/wireless.d/$ssid"; network::network::write_interface_settings($wireless_net, $wireless_file); - network::wireless::wpa_supplicant_add_network($wireless_net->{WIRELESS_ESSID}, $wireless_enc_mode, $wireless_enc_key); - system('/usr/sbin/wpa_cli reconfigure'); #- this should be handled by the monitoring daemon instead + if ($has_roaming) { + #- this should be handled by the monitoring daemon instead + run_program::run('/usr/sbin/wpa_cli', 'reconfigure'); + } else { + overwrite_wireless_ifcfg($wireless_net); + } 1; } -sub connect_to_selected() { - my ($selected) = $wireless_list->get_selected_indices or return; - my $ap = $wireless_list->{data}[$selected][0]; - my $network = $wireless_networks->{$ap}; - - if (defined $network->{id}) { - eval { $monitor->select_network($network->{id}) }; - $@ and err_dialog(N("Wireless connection"), N("Unable to contact daemon")); - } else { - configure_selected(); - #- apply config in wpa_supplicant and retry - } +sub overwrite_wireless_ifcfg { + my ($wireless_net) = @_; + my $ifcfg = $net->{ifcfg}{$wireless_device} ||= {}; + delete $ifcfg->{$_} foreach grep { /wireless/i } keys %$ifcfg; + put_in_hash($ifcfg, $wireless_net); + network::network::write_interface_conf($net, $wireless_device); +} +sub wait_and_run_sub { + my ($time, $sub) = @_; gtkset_mousecursor_wait(); - - Glib::Timeout->add(5000, sub { - update_networks(); + Glib::Timeout->add($time, sub { + $sub->(); gtkset_mousecursor_normal(); 0; }); } +sub connect_to_ap { + my ($ap, $o_disable_configure) = @_; + my $network = $wireless_networks->{$ap}; + my $found; + + if ($network) { + my $wireless_net = !$has_roaming && ($net->{wireless}{$ap} || $net->{wireless}{$network->{essid}}); + if (defined $network->{id}) { + eval { $monitor->select_network($network->{id}) }; + $found = !$@; + $found or err_dialog(N("Wireless connection"), N("Unable to contact daemon")); + } elsif ($wireless_net) { + network::tools::stop_interface($wireless_device, 0); + overwrite_wireless_ifcfg($wireless_net); + network::tools::start_interface($wireless_device, 1); + $found = 1; + } + } + + $found || !$o_disable_configure or return; + + if (!$found) { + if ($has_roaming) { + configure_ap($ap); + #- wait for wpa_supplicant to reconfigure the device + wait_and_run_sub(2000, sub { connect_to_ap($ap, 1) }); + return; + } else { + network::tools::stop_interface($wireless_device, 0); + configure_ap($ap); + network::tools::start_interface($wireless_device, 0); + } + } + wait_and_run_sub(5000, \&update_networks); +} + +sub configure_selected() { + my ($selected) = $wireless_list->get_selected_indices or return; + configure_ap($wireless_list->{data}[$selected][0]); +} + +sub connect_to_selected() { + my ($selected) = $wireless_list->get_selected_indices or return; + connect_to_ap($wireless_list->{data}[$selected][0]); +} + update_networks(); Glib::Timeout->add(30000, \&update_networks); @@ -160,7 +221,7 @@ gtkadd($w->{window}, gtknew('VBox', spacing => 5, children => [ $::isEmbedded ? () : (0, Gtk2::Banner->new('/usr/share/mcc/themes/default/drakroam-mdk.png', N("Wireless connection"))), 1, gtknew('HBox', spacing => 5, children => [ - 1, gtknew('ScrolledWindow', width => 420, height => 300, child => $wireless_list), + 1, gtknew('ScrolledWindow', width => 500, height => 300, child => $wireless_list), 0, gtknew('VButtonBox', layout => 'edge', children_loose => [ gtknew('Button', text => N("Configure"), clicked => \&configure_selected), gtknew('Button', text => N("Connect"), clicked => \&connect_to_selected), @@ -169,5 +230,8 @@ gtkadd($w->{window}, ]), ]), ]), - ); + ); + +$arg_ap and Glib::Timeout->add(100, sub { connect_to_ap($arg_ap); 0 }); + $w->main; diff --git a/perl-install/standalone/net_applet b/perl-install/standalone/net_applet index 939c697f7..bfc751064 100644 --- a/perl-install/standalone/net_applet +++ b/perl-install/standalone/net_applet @@ -21,11 +21,11 @@ use ugtk2 qw(:create :helpers :wrappers :dialogs); my $onstartupfile = "$ENV{HOME}/.net_applet"; shouldStart() or die "$onstartupfile should be set to TRUE or use net_applet --force"; -# Allow multiple instances, but only one per user: +#- Allow multiple instances, but only one per user: is_running('net_applet') and die "net_applet already running\n"; my ($eventbox, $img, $bubble); -my ($current_state, $current_interface, $menu, $wireless_menu, $timeout, $update_timeout); +my ($current_state, $current_interface, $menu, $wireless_device, $wireless_menu, $timeout, $update_timeout); add_icon_path("/usr/share/libDrakX/pixmaps/"); my $net = {}; @@ -57,7 +57,7 @@ my %actions = ( 'downNetwork' => { name => sub { N("Disconnect %s", $_[0]) }, launch => sub { network::tools::stop_interface($_[0], 1) } }, 'monitorNetwork' => { name => N("Monitor Network"), launch => \&run_net_monitor }, 'monitorIFW' => { name => N("Interactive Firewall"), launch => \&run_drakids }, - 'wireless' => { name => N("Manage wireless networks"), launch => \&run_drakroam }, + 'wireless' => { name => N("Manage wireless networks"), launch => sub { run_drakroam() } }, 'confNetwork' => { name => N("Configure Network"), launch => sub { system("/usr/sbin/drakconnect --skip-wizard &") } }, 'chooseInterface' => { name => N("Watched interface"), @@ -155,8 +155,9 @@ sub shouldStart() { sub run_net_monitor() { run_program::raw({ detach => 1 }, '/usr/sbin/net_monitor', '--defaultintf', $current_interface) unless is_running('net_monitor'); } -sub run_drakroam() { - run_program::raw({ detach => 1 }, '/usr/sbin/drakroam') unless is_running('drakroam'); +sub run_drakroam { + my ($o_ap) = @_; + run_program::raw({ detach => 1 }, '/usr/sbin/drakroam', if_($o_ap, "--ap=$o_ap")) unless is_running('drakroam'); } sub run_drakids() { $ifw_alert = 0; @@ -167,7 +168,7 @@ sub run_drakids() { } } sub generate_wireless_menuitem { - my ($net) = @_; + my ($net, $ap) = @_; $net->{menuitem} = Gtk2::CheckMenuItem->new; $net->{menuitem}->set_draw_as_radio(1); $net->{menuitem}->add(gtkpack_(gtkshow(Gtk2::HBox->new), @@ -179,7 +180,7 @@ sub generate_wireless_menuitem { eval { $monitor->select_network($net->{id}) }; $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); } else { - run_drakroam(); + run_drakroam($ap); } checkNetworkForce(); }); @@ -187,7 +188,7 @@ sub generate_wireless_menuitem { } sub update_wireless_item { my ($net, $ap_address) = @_; - $net->{ssid_label}->set_text($net->{ssid} || "[$ap_address]"); + $net->{ssid_label}->set_text($net->{essid} || "[$ap_address]"); $net->{keyring_image}->visible(to_bool($net->{flags})); $net->{level_image}->set_from_pixbuf($pixbufs{link_level}{$net->{approx_level}}); @@ -196,11 +197,12 @@ sub update_wireless_item { $net->{menuitem}->signal_handler_unblock($net->{activate}); } sub checkWireless() { - my $networks = eval { $monitor->list_wireless }; + $wireless_device or return; + my ($networks) = network::monitor::list_wireless($monitor, $wireless_device); foreach (keys %$networks) { my $net = $wireless_networks{$_} ||= {}; put_in_hash($net, $networks->{$_}); - exists $net->{menuitem} or generate_wireless_menuitem($net); + exists $net->{menuitem} or generate_wireless_menuitem($net, $_); update_wireless_item($net, $_); } $wireless_networks{$_}{menuitem}->visible(exists $networks->{$_}) foreach keys %wireless_networks; @@ -215,6 +217,7 @@ sub checkNetworkForce() { $net = {}; network::network::read_net_conf($net); undef $current_state; + $wireless_device = detect_devices::get_wireless_interface(); checkWireless(); checkNetwork(); } @@ -231,6 +234,7 @@ sub go2State { if ($current_state ne $state_type || $current_interface ne $interface) { $current_state = $state_type; $current_interface = $interface; + $wireless_device = detect_devices::get_wireless_interface(); if ($menu) { if (my $m = $wireless_menu && $wireless_menu->get_submenu) { $_->{menuitem}->get_parent and $m->remove($_->{menuitem}) foreach values %wireless_networks; @@ -283,7 +287,6 @@ sub generate_menu { }; my (@settings); - my $has_wireless = $monitor && detect_devices::has_wireless(); my $interactive; eval { $interactive = $ifw->get_interactive }; @@ -296,7 +299,7 @@ sub generate_menu { $menu->append($create_item->('confNetwork')); if ($current_state ne 'notconfigured') { - $menu->append($create_item->('wireless')) if $has_wireless; + $menu->append($create_item->('wireless')) if $wireless_device; push @settings, $create_item->('chooseInterface'); } @@ -311,7 +314,7 @@ sub generate_menu { toggled => sub { setAutoStart(uc(bool2text($_[0]->get_active))) })); $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); - $has_wireless and $menu->append(gtkshow($wireless_menu = create_menu(N("Wireless networks"), + $wireless_device and $menu->append(gtkshow($wireless_menu = create_menu(N("Wireless networks"), map { $_->{menuitem} } values %wireless_networks))); $menu->append(gtkshow(create_menu(N("Settings"), grep { $_ } @settings))); $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); -- cgit v1.2.1