diff options
Diffstat (limited to 'lib/network/monitor.pm')
-rw-r--r-- | lib/network/monitor.pm | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/network/monitor.pm b/lib/network/monitor.pm new file mode 100644 index 0000000..7e644b6 --- /dev/null +++ b/lib/network/monitor.pm @@ -0,0 +1,136 @@ +package network::monitor; + +use common; +use dbus_object; + +our @ISA = qw(dbus_object); + +my $monitor_service = "com.mandriva.monitoring"; +my $monitor_path = "/com/mandriva/monitoring/wireless"; +my $monitor_interface = "com.mandriva.monitoring.wireless"; + +sub new { + my ($type, $bus) = @_; + dbus_object::new($type, $bus, $monitor_service, $monitor_path, $monitor_interface); +} + +sub list_wireless { + my ($monitor, $o_intf) = @_; + my ($results, $list, %networks); + my $has_roaming; + #- first try to use mandi + eval { + $results = $monitor->call_method('ScanResults'); + $list = $monitor->call_method('ListNetworks'); + $has_roaming = 1; + } if $monitor; + #- try wpa_cli if we're root + if (!$has_roaming && !$>) { + $results = `/usr/sbin/wpa_cli scan_results 2>/dev/null`; + $list = `/usr/sbin/wpa_cli list_networks 2>/dev/null`; + $_ =~ s/^Selected interface (.*)\n//g foreach $results, $list; + } + if ($results && $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) { + my ($ap, $frequency, $signal_strength, $flags, $essid) = ($1, $2, $3, $4, $5); + $networks{$ap}{ap} ||= $ap; + #- wpa_supplicant may list the network two times, use ||= + $networks{$ap}{frequency} ||= $frequency; + $networks{$ap}{signal_strength} ||= $signal_strength; + my $adhoc = $flags =~ s/\[ibss\]//i; + $networks{$ap}{mode} ||= $adhoc ? "Ad-Hoc" : "Managed"; + $networks{$ap}{flags} ||= $flags; + $networks{$ap}{essid} ||= $essid; + } + if (any { $_->{signal_strength} > 100 } values %networks) { + #- signal level is really too high in wpa_supplicant + #- this should be standardized at some point + $_->{signal_strength} = int($_->{signal_strength}/3.5) + foreach values %networks; + } + + #- network id / ssid / bssid / flags + while ($list =~ /^(\d+)\t(.*?)\t(.*?)\t(.*)$/mg) { + foreach my $net (uniq(if_($networks{$3}, $networks{$3}), grep { $_->{essid} eq $2 } values(%networks))) { + $net->{ap} = $3 if $3 ne 'any'; + $net->{id} = $1; + $net->{essid} ||= $2; + $net->{current} = to_bool($4 eq '[CURRENT]'); + } + } + } else { + #- else use iwlist + require network::connection::wireless; + my ($current_essid, $current_ap) = network::connection::wireless::get_access_point($o_intf); + if ($o_intf && !$> && !`/sbin/ip link show $o_intf up`) { + system("/sbin/ip link set $o_intf up"); + } + my @list = `/sbin/iwlist $o_intf scanning 2>/dev/null`; + my $net = {}; + my $quality_match = qr/Quality[:=](\S*)/; + my $eval_quality = sub { + my ($qual) = @_; + $qual =~ s!/0+$!/255!; #- prism54 reports quality with division by zero + $qual =~ m!/! ? eval($qual)*100 : $qual; + }; + my ($has_key, $has_wpa, $has_eap); + foreach (@list) { + if ((/^\s*$/ || /Cell/) && exists $net->{ap}) { + $net->{current} = to_bool($net->{ap} ? $net->{ap} eq $current_ap : $net->{essid} && $net->{essid} eq $current_essid); + $net->{flags} = $has_wpa ? '[WPA]' : $has_key ? '[WEP]' : ''; + $net->{flags} .= '[EAP]' if $has_eap; + $networks{$net->{ap}} = $net; + $net = {}; + $has_key = $has_wpa = $has_eap = undef; + } + /Address: (.*)/ and $net->{ap} = lc($1); + /ESSID:"(.*?)"/ and $net->{essid} = $1; + /Mode:(\S*)/ and $net->{mode} = $1; + $net->{mode} = 'Managed' if $net->{mode} eq 'Master'; + $_ =~ $quality_match and $net->{signal_strength} = $eval_quality->($1); + m|Signal level[:=]([0-9]+/[0-9]+)| and $net->{signal_level} = $eval_quality->($1); + /key:(\S*)\s/ && $1 eq 'on' and $has_key = 1; + /Extra:wpa_ie=|IE:.*WPA/ and $has_wpa = 1; + /Authentication Suites \(\d+\) :.*\b802\.1x\b/ and $has_eap = 1; + } + my $incorrect_quality = + (every { $_->{signal_strength} == 100 } values %networks) && + (any { $_->{signal_strength} != $_->{signal_level} } values %networks); + foreach (values %networks) { + my $level = delete $_->{signal_level}; + $_->{signal_strength} ||= $level; + $_->{signal_strength} = $level if $incorrect_quality; + } + if ($current_ap && exists $networks{$current_ap}) { + foreach (`/sbin/iwconfig $o_intf 2>/dev/null`) { + my $quality = $_ =~ $quality_match && $eval_quality->($1); + $networks{$current_ap}{signal_strength} = $quality if $quality; + } + } + } + + foreach (values %networks) { + $_->{hidden} = member($_->{essid}, '', '<hidden>'); + $_->{essid} eq '<hidden>' and undef $_->{essid}; + $_->{name} = $_->{essid} || "[$_->{ap}]"; + } + (\%networks, $has_roaming); +} + +sub select_network { + my ($o, $id) = @_; + my $method = 'SelectNetwork'; + if ($o) { + $o->call_method($method, Net::DBus::dbus_uint32($id)); + } else { + require run_program; + run_program::run("dbus-send", "--system", "--type=method_call", + "--dest=" . $monitor_service, + $monitor_path, + $monitor_interface . '.' . $method, + 'uint32:' . $id); + } +} + +1; |