summaryrefslogtreecommitdiffstats
path: root/lib/network/monitor.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/network/monitor.pm')
-rw-r--r--lib/network/monitor.pm136
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;