Saturday, March 15, 2008

netz.pl

Gentoo's baselayout tends to not work so well for wireless, and it only tries each SSID once before skipping to the next, regardless of multiple APs. Because of this, I decided to write my own script which runs dhclient, iwlist, iwconfig, and ifconfig to set the interface up. This script is a bit limited and rough since the MAC address stuff isn't actually used, and the preferred SSIDs are defined in the file (as are the MAC addresses).

netz.pl

#!/usr/bin/perl -w
use strict;
use warnings;

scalar @ARGV || die "Usage: $0 iface [ MACmode ]\n";
my $iface = shift @ARGV;
my %macs = ('default' => '00:00:00:00:00:00', 'alt1' => '00:00:00:00:00:00');
my $mac = $macs{default};
scalar @ARGV && ($mac = $macs{$ARGV[0]});
system("ifconfig $iface up");# || die "No such interface: $iface\n";
open(IWCONFIG, "iwlist $iface scanning|") || die "Unable to find iwlist.\n";
my @lines = <IWCONFIG>;
chomp(@lines);
close(IWCONFIG);
scalar @lines || die "No wireless extensions on $iface\n";

system('killall dhclient');


my %aps;
my @tline = ();
our @preferred = ('UniversityOfWashingtonCSE', 'EE', 'University of Washington');
foreach(@lines) {
if(/^\s+Cell [0-9][0-9] - Address: [0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}/) {
if(scalar @tline) {
my %tap = &newap(@tline);
my $tqual = &zerolead(2, $tap{quality});
if($aps{$tap{quality}}) {
push(@{$aps{$tqual}}, \%tap);
}
else {
$aps{$tqual} = [\%tap];
}
@tline = ();
}
push(@tline, $_);
}
elsif(/ESSID:"[^"]+"/ || /Mode:[A-Za-z]+/ || /Frequency:[0-9.]+\s.Hz \(Channel [0-9]+\)/ || /Quality=[0-9]+\/70/) {
push(@tline, $_);
}
}
my @picked;
my @keys = reverse sort keys %aps;
my $found = 0;
for(my $i = 0; $i < scalar @keys; $i++) {
my @sublist = @{$aps{$keys[$i]}};
for(my $q = 0; $q < scalar @sublist; $q++) {
my %ap = %{$sublist[$q]};
(push(@picked, \%ap)) and ($found = 1) if(&arrayfind($ap{ssid}, @preferred) >= 0);
}
}
$found || die "Unable to choose access point for $iface\n";
$found = 0;
for(my $i = 0; !$found && $i < scalar @picked; $i++) {
$found = 0;
my %chosen = %{$picked[$i]};
print "$chosen{ssid} : $chosen{ap} {\n\tQuality: $chosen{quality}/70\n\tChannel: $chosen{channel}\n\tMode: $chosen{mode}\n}\n\n";
system("iwconfig $iface ap $chosen{ap} essid \"$chosen{ssid}\"");
open(DHCP, "dhclient $iface 2>&1 |") || die "Unable to find dhclient.\n";
@lines = <DHCP>;
close(DHCP);
(scalar grep(/No DHCPOFFERS received\./, @lines) && print "Unable to get DHCP lease on $iface.\n\n") || ($found = 1);
if($found) {
open(NSLOOKUP, "nslookup -timeout=5 google.com|");
@lines = <NSLOOKUP>;
close(NSLOOKUP);
(scalar grep(/connection timed out/i, @lines) || scalar grep(/NXDOMAIN/, @lines)) && (print "Unable to find google.com via DNS over $iface.\n") && ($found = 0);
}
}
$found || die "Unable to get connection on $iface\n";



sub zerolead {
my $len = shift;
my $str = shift;
($str = '0' . $str) while(length($str) < $len);
return $str;
}
sub newap {
my @text = @_;
my %self = ('standard' => '', 'ssid' => '', 'mode' => '', 'frequency' => '', 'ap' => '', 'quality' => '', 'channel' => '');
foreach(@text) {
if(/^\s+Cell [0-9][0-9] - Address: ([0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2})/) {
$self{ap} = $1;
}
elsif(/ESSID:"([^"]+)"/) {
$self{ssid} = $1;
}
elsif(/Mode:([A-Za-z-]+)/) {
$self{mode} = $1;
}
elsif(/Frequency:([0-9.]+\s.Hz) \(Channel ([0-9]+)\)/) {
($self{frequency}, $self{channel}) = ($1, $2);
}
elsif(/Quality=([0-9]+)\/70/) {
$self{quality} = $1;
}
}
return %self;
}
sub arrayfind {
my $term = shift;
my @find = @_;
for(my $i = 0; $i < scalar @find; $i++) {
return $i if($term eq $find[$i]);
}
return -1;
}

No comments: