diff options
Diffstat (limited to 'lib/network')
39 files changed, 4873 insertions, 2534 deletions
diff --git a/lib/network/.perl_checker b/lib/network/.perl_checker new file mode 100644 index 0000000..2326e2f --- /dev/null +++ b/lib/network/.perl_checker @@ -0,0 +1 @@ +Basedir ../.. diff --git a/lib/network/adsl.pm b/lib/network/adsl.pm index 3768c17..c012219 100644 --- a/lib/network/adsl.pm +++ b/lib/network/adsl.pm @@ -4,10 +4,6 @@ use common; use run_program; use network::tools; use modules; -use vars qw(@ISA @EXPORT); - -@ISA = qw(Exporter); -@EXPORT = qw(adsl_conf_backend); sub adsl_probe_info { my ($net) = @_; @@ -16,12 +12,16 @@ sub adsl_probe_info { foreach (qw(/etc/ppp/peers/ppp0 /etc/ppp/options /etc/ppp/options.adsl)) { ($login) = map { if_(/^user\s+"([^"]+)"/, $1) } cat_("$::prefix/$_") if !$login && -r "$::prefix/$_"; } - my %pppoe_conf; %pppoe_conf = getVarsFromSh($pppoe_file) if (!exists $net->{adsl}{method} || $net->{adsl}{method} eq 'pppoe') && -f $pppoe_file; - $login ||= $pppoe_conf{USER}; + my %pppoe_conf = -f $pppoe_file && getVarsFromSh($pppoe_file); + $login = $pppoe_conf{USER} if !$login || $net->{adsl}{method} eq 'pppoe'; my $passwd = network::tools::passwd_by_login($login); if (!$net->{adsl}{vpi} && !$net->{adsl}{vci}) { - ($net->{adsl}{vpi}, $net->{adsl}{vci}) = - (map { if_(/^.*-vpi\s+(\d+)\s+-vci\s+(\d+)/, map { sprintf("%x", $_) } $1, $2) } cat_("$::prefix/etc/ppp/peers/ppp0")); + foreach (cat_("$::prefix/etc/ppp/peers/ppp0")) { + if (/^.*-vpi\s+(\d+)\s+-vci\s+(\d+)/ || /^plugin pppoatm.so (\d+)\.(\d+)$/) { + ($net->{adsl}{vpi}, $net->{adsl}{vci}) = ($1, $2); + last; + } + } } $pppoe_conf{DNS1} ||= ''; $pppoe_conf{DNS2} ||= ''; @@ -29,308 +29,24 @@ sub adsl_probe_info { add2hash($net->{adsl}, { login => $login, passwd => $passwd }); } -sub adsl_detect() { - require list_modules; - require detect_devices; - my @modules = list_modules::category2modules('network/usb_dsl'); - # return an hash compatible with what drakconnect expect us to return: - my %compat = ( - 'speedtch' => 'speedtouch', - 'eagle-usb' => 'sagem', - ); - - return { - bewan => [ detect_devices::getBewan() ], - eci => [ detect_devices::getECI() ], - map { $compat{$_} || $_ => [ detect_devices::matching_driver($_) ] } @modules, - }; -} - -sub sagem_set_parameters { - my ($net) = @_; - my %l = map { $_ => sprintf("%08s", $net->{adsl}{$_}) } qw(vci vpi Encapsulation); - - my $static_ip = $net->{adsl}{method} eq 'static' && $net->{ifcfg}{sagem}{IPADDR}; - foreach my $cfg_file (qw(/etc/analog/adiusbadsl.conf /etc/eagle-usb/eagle-usb.conf)) { - substInFile { - s/Linetype=.*\n/Linetype=0000000A\n/; #- use CMVs - s/VCI=.*\n/VCI=$l{vci}\n/; - s/VPI=.*\n/VPI=$l{vpi}\n/; - s/Encapsulation=.*\n/Encapsulation=$l{Encapsulation}\n/; - s/ISP=.*\n/ISP=$net->{adsl}{provider_id}\n/; - s/STATIC_IP=.*\n//; - s!</eaglectrl>!STATIC_IP=$static_ip\n</eaglectrl>! if $static_ip; - } "$::prefix$cfg_file"; - } - #- create CMV symlinks for both POTS and ISDN lines - foreach my $type (qw(p i)) { - my $cmv; - my ($country) = $net->{adsl}{provider_id} =~ /^([a-zA-Z]+)\d+$/; - #- try to find a CMV for this specific ISP - $cmv = "$::prefix/etc/eagle-usb/CMVe${type}$net->{adsl}{provider_id}.txt" if $net->{adsl}{provider_id}; - #- if not found, try to found a CMV for the country - -f $cmv or $cmv = "$::prefix/etc/eagle-usb/CMVe${type}${country}.txt"; - #- fallback on the generic CMV if no other matched - -f $cmv or $cmv = "$::prefix/etc/eagle-usb/CMVe${type}WO.txt"; - symlinkf($cmv, "$::prefix/etc/eagle-usb/CMVe${type}.txt"); - } - #- remove this otherwise eaglectrl won't start - unlink("$::prefix/etc/eagle-usb/eagle-usb_must_be_configured"); -} - sub adsl_conf_backend { - my ($in, $modules_conf, $net) = @_; - - my $bewan_module; - $bewan_module = $net->{adsl}{bus} eq 'PCI' ? 'unicorn_pci_atm' : 'unicorn_usb_atm' if $net->{adsl}{device} eq "bewan"; - - my $adsl_type = $net->{adsl}{method}; - my $adsl_device = $net->{adsl}{device}; - - # all supported modems came with their own pppoa module, so no need for "plugin pppoatm.so" - my %modems = - ( - bewan => - { - start => qq( -# ActivationMode=1 -modprobe $bewan_module -# wait for the modem to be set up: -sleep 10 -), - stop => qq(modprobe -r $bewan_module), - plugin => { - pppoa => "pppoatm.so " . join('.', hex($net->{adsl}{vpi}), hex($net->{adsl}{vci})) - }, - ppp_options => qq( -default-asyncmap -hide-password -noaccomp -nobsdcomp -nodeflate -novj novjccomp -lcp-echo-interval 20 -lcp-echo-failure 3 -sync -), - }, - - speedtouch => - { - modules => [ qw(speedtch) ], - start => '/usr/bin/speedtouch-start --nocall', - overide_script => 1, - server => { - pppoa => qq("/usr/sbin/pppoa3 -c") - }, - plugin => { - pppoa => "pppoatm.so " . join('.', hex($net->{adsl}{vpi}), hex($net->{adsl}{vci})), - }, - ppp_options => qq( -sync -noaccomp), - aliases => [ - ['char-major-108', 'ppp_generic'], - ['tty-ldisc-3', 'ppp_async'], - ['tty-ldisc-13', 'n_hdlc'], - ['tty-ldisc-14', 'ppp_synctty'], - ['ppp-compress-21', 'bsd_comp'], - ['ppp-compress-24', 'ppp_deflate'], - ['ppp-compress-26', 'ppp_deflate'] - ], - }, - - sagem => - { - modules => [ qw(eagle-usb) ], - start => '/sbin/eaglectrl -i >/dev/null 2>/dev/null || /sbin/eaglectrl -d', - stop => "/usr/bin/killall pppoa", - get_intf => '/sbin/eaglectrl -i', - server => { - pppoa => q("/sbin/fctStartAdsl -t 1 -i"), - }, - ppp_options => qq( -mru 1492 -mtu 1492 -nobsdcomp -nodeflate -noaccomp -am -novjccomp), - aliases => [ - ['char-major-108', 'ppp_generic'], - ['tty-ldisc-3', 'ppp_async'], - ['tty-ldisc-13', 'n_hdlc'], - ['tty-ldisc-14', 'ppp_synctty'] - ], - }, - - eci => - { - start => '/usr/bin/startmodem', - server => { - pppoe => qq("/usr/bin/pppoeci -v 1 -vpi $net->{adsl}{vpi} -vci $net->{adsl}{vci}"), - }, - ppp_options => qq( -noipdefault -sync -noaccomp -linkname eciadsl -lcp-echo-interval 0) - }, - - pptp_modem => - { - server => { - pptp => qq("/usr/sbin/pptp 10.0.0.138 --nolaunchpppd"), - }, - }, - - capi_modem => - { - ppp_options => qq( -connect /bin/true -ipcp-accept-remote -ipcp-accept-local - -sync -noauth -lcp-echo-interval 5 -lcp-echo-failure 3 -lcp-max-configure 50 -lcp-max-terminate 2 - -noccp -noipx -mru 1492 -mtu 1492), - plugin => { - capi => qq(capiplugin.so -avmadsl) - }, - }, - ); - - my %generic = - ( - pppoe => - { - server => '"pppoe -I ' . (exists $modems{$adsl_device}{get_intf} ? "`$modems{$adsl_device}{get_intf}`" : $net->{adsl}{ethernet_device}) . '"', - ppp_options => qq(default-asyncmap -mru 1492 -mtu 1492 -noaccomp -noccp -nobsdcomp -novjccomp -nodeflate -lcp-echo-interval 20 -lcp-echo-failure 3 -), - } - ); - - if ($adsl_type =~ /^pp|^capi$/) { - mkdir_p("$::prefix/etc/ppp"); - $in->do_pkgs->install('ppp'); - my %packages = ( - pppoa => [ qw(ppp-pppoatm) ], - pppoe => [ qw(ppp-pppoe rp-pppoe) ], - pptp => [ qw(pptp-linux) ], - capi => [ qw(isdn4k-utils) ], #- capi4linux service - ); - $in->do_pkgs->install(@{$packages{$adsl_type}}); - - my $pty_option = - exists $modems{$adsl_device}{server}{$adsl_type} ? "pty $modems{$adsl_device}{server}{$adsl_type}" : - exists $generic{$adsl_type}{server} ? "pty $generic{$adsl_type}{server}" : - ""; - my $plugin = exists $modems{$adsl_device}{plugin}{$adsl_type} && "plugin $modems{$adsl_device}{plugin}{$adsl_type}"; - my $noipdefault = $adsl_type eq 'pptp' ? '' : 'noipdefault'; - my $ppp_options = - exists $modems{$adsl_device}{ppp_options} ? $modems{$adsl_device}{ppp_options} : - exists $generic{$adsl_type}{ppp_options} ? $generic{$adsl_type}{ppp_options} : - ""; - output("$::prefix/etc/ppp/peers/ppp0", -qq(lock -persist -noauth -usepeerdns -defaultroute -$noipdefault -$ppp_options -kdebug 1 -nopcomp -noccp -novj -holdoff 4 -maxfail 25 -$pty_option -$plugin -user "$net->{adsl}{login}" -)); - - network::tools::write_secret_backend($net->{adsl}{login}, $net->{adsl}{passwd}); - - my $ethernet_device = $net->{adsl}{ethernet_device}; - if ($ethernet_device =~ /^eth/) { - $net->{ifcfg}{$ethernet_device} = { - DEVICE => $ethernet_device, - BOOTPROTO => 'none', - NETMASK => '255.255.255.0', - NETWORK => '10.0.0.0', - BROADCAST => '10.0.0.255', - MII_NOT_SUPPORTED => 'yes', - ONBOOT => 'yes', - }; - } - } - - #- FIXME: ppp0 and ippp0 are hardcoded - my $metric = network::tools::get_default_metric("adsl"); #- FIXME, do not override if already set - put_in_hash($net->{ifcfg}{ppp0} ||= {}, { - DEVICE => 'ppp0', - TYPE => 'ADSL', - METRIC => $metric, - }) unless member($adsl_type, qw(static dhcp)); - #- don't overwrite ONBOOT setting, it may have been handled earlier in netconnect - $net->{ifcfg}{ppp0}{ONBOOT} ||= 'yes'; - - #- remove file used with sagem for dhcp/static connections - unlink("$::prefix/etc/sysconfig/network-scripts/ifcfg-sagem"); - - #- set vpi, vci and encapsulation parameters for sagem - $adsl_device eq 'sagem' and sagem_set_parameters($net); - - #- set aliases - if (exists $modems{$adsl_device}{aliases}) { - $modules_conf->set_alias($_->[0], $_->[1]) foreach @{$modems{$adsl_device}{aliases}}; - $::isStandalone and $modules_conf->write; - } - #- remove the "speedtch off" alias that was written by Mandrakelinux 10.0 - $adsl_device eq 'speedtouch' and $modules_conf->remove_alias('speedtch'); - - if ($adsl_type eq "capi") { - require network::isdn; - network::isdn::setup_capi_conf($in, $net->{adsl}{capi_card}); - services::disable('isdn4linux'); - services::enable('capi4linux'); - - #- install and run drdsl for dsl connections, once capi driver is loaded - $in->do_pkgs->ensure_is_installed_if_available("drdsl", "/usr/sbin/drdsl"); - run_program::rooted($::prefix, "/usr/sbin/drdsl"); - } - - #- load modules and run modem-specific start programs - #- useful during install, or in case the packages have been installed after the device has been plugged - my @modules = (@{$modems{$adsl_device}{modules}}, map { $_->[1] } @{$modems{$adsl_device}{aliases}}); - @modules or @modules = qw(ppp_synctty ppp_async ppp_generic n_hdlc); #- required for pppoe/pptp connections - #- pppoa connections need the pppoatm module - #- pppd should run "modprobe pppoatm", but it will fail during install - push @modules, 'pppoatm' if $adsl_type eq 'pppoa'; - foreach (@modules) { - eval { modules::load($_) } or log::l("failed to load $_ module: $@"); - } - $modems{$adsl_device}{start} and run_program::rooted($::prefix, $modems{$adsl_device}{start}); + my ($in, $net) = @_; + + require network::connection::xdsl; + my $xdsl = network::connection::xdsl->new( + $net->{adsl}{method} eq "capi" ? + $net->{adsl}{capi_card} : + { driver => $net->{adsl}{driver}, ethernet_device => $net->{adsl}{ethernet_device} }); + $xdsl->{protocol} = $net->{adsl}{method}; + $xdsl->{access}{login} = $net->{adsl}{login}; + $xdsl->{access}{password} = $net->{adsl}{passwd}; + $xdsl->{access}{vpi} = $net->{adsl}{vpi}; + $xdsl->{access}{vci} = $net->{adsl}{vci}; + + $xdsl->install_packages($in); + $xdsl->unload_connection; + $xdsl->write_settings($net); + $xdsl->prepare_connection; } 1; diff --git a/lib/network/connection.pm b/lib/network/connection.pm new file mode 100644 index 0000000..0088ede --- /dev/null +++ b/lib/network/connection.pm @@ -0,0 +1,235 @@ +package network::connection; + +use common; +use network::vpn; + +sub get_types { + sort { $a->get_metric <=> $b->get_metric } grep { $_->can('get_devices') } common::load_modules_from_base(__PACKAGE__); +} + +=item get_type_name() + +Get the connection type name, unstranslated + +=cut + +sub get_type_name() { N("Unknown connection type") } +sub get_type_description { + my ($class) = @_; + $class->get_type_name; +} + +=item get_type_icon() + +Get the connection type icon path + +=cut + +sub get_type_icon() { '/usr/share/mcc/themes/default/drakconnect-mdk.png' } + +=item get_devices() + +Get the devices supported by this connection type + +=cut + +=item get_connections() + +List connections that can be configured by the class + +=cut + +sub get_connections { + my ($class, %options) = @_; + map { $class->new($_) } $class->get_devices(%options); +} + +=item find_ifcfg_type($ifcfg) + +Returns the class matching the connection type of the ifcfg hash + +=cut + +sub find_ifcfg_type { + my ($_class, $ifcfg) = @_; + find { $_->can('handles_ifcfg') && $_->handles_ifcfg($ifcfg) } sort { $b->get_metric <=> $a->get_metric } get_types(); +} + +sub new { + my ($class, $device) = @_; + bless { + device => $device, + settings => {}, + networks => {}, + }, $class; +} + +sub get_description { + my ($self) = @_; + $self->{device}{description}; +} + +sub get_driver { + my ($self) = @_; + $self->{device}{driver}; +} + +sub get_interface { + my ($_self) = @_; + die "unable to get interface"; +} + +sub get_metric { 60 } + +sub get_status { + my ($self) = @_; + require network::tools; + my ($_is_up, $gw_address) = network::tools::get_interface_status($self->get_interface); + $self->{status} = to_bool($gw_address); +} + +sub get_ifcfg_bool { + my ($self, $field) = @_; + defined $self->{ifcfg}{$field} ? text2bool($self->{ifcfg}{$field}) : undef; +} + +sub get_selected_network { + my ($self) = @_; + exists $self->{networks}{$self->{network}} && $self->{networks}{$self->{network}}; +} + +sub load_interface_settings { + my ($self) = @_; + require network::network; + my $file = network::network::get_ifcfg_file($self->get_interface); + $self->{ifcfg} = { getVarsFromSh($file) }; + $self->{vpn_list} = [ map { $_->get_configured_connections } network::vpn->list_types ]; + $self->{control}{onboot} = $self->get_ifcfg_bool('ONBOOT'); + $self->{control}{userctl} = $self->get_ifcfg_bool('USERCTL'); + $self->{control}{metric} = $self->{ifcfg}{METRIC}; +} + +#- override to return 1 if the connection network scan is slow +sub network_scan_is_slow { 0 } + +sub get_network_access_settings_label { N("Network access settings") } +sub get_access_settings_label { N("Access settings") } +sub get_address_settings_label { N("Address settings") } + +sub set_provider { + my ($self, $provider_data) = @_; + $self->{provider} = $provider_data; +} + +#- check that $self->can('get_protocols') first +sub get_protocol_settings { + my ($self) = @_; + my $protocols = $self->get_protocols; + [ + { + val => \$self->{protocol}, type => 'list', + list => [ sort { $protocols->{$a} cmp $protocols->{$b} } keys %$protocols ], + format => sub { $protocols->{$_[0]} }, + } + ]; +} + +sub guess_network_control_settings { + my ($self) = @_; + $self->{control}{vpn} = find { + $self->{ifcfg}{VPN_TYPE} eq $_->get_type && + $self->{ifcfg}{VPN_NAME} eq $_->get_name; + } @{$self->{vpn_list}}; +} + +sub get_network_control_settings { + my ($self) = @_; + [ + if_(@{$self->{vpn_list}}, + { label => N("VPN connection"), val => \$self->{control}{vpn}, + list => [ undef, @{$self->{vpn_list}} ], + format => sub { defined $_[0] ? $_[0]->get_label : N("None") } }), + ]; +} + +sub guess_control_settings { + my ($self) = @_; + $self->{control}{metric} ||= $self->get_metric; +} + +sub get_control_settings { + my ($self) = @_; + [ + { text => N("Allow users to manage the connection"), val => \$self->{control}{userctl}, type => "bool" }, + { text => N("Start the connection at boot"), val => \$self->{control}{onboot}, type => "bool" }, + { label => N("Metric"), val => \$self->{control}{metric}, advanced => 1 }, + ]; +} + +sub build_ifcfg_settings { + my ($self, $o_options) = @_; + put_in_hash($o_options, { + DEVICE => $self->get_interface, + ONBOOT => bool2yesno($self->{control}{onboot}), + USERCTL => bool2yesno($self->{control}{userctl}), + METRIC => $self->{control}{metric}, + VPN_TYPE => defined $self->{control}{vpn} && $self->{control}{vpn}->get_type, + VPN_NAME => defined $self->{control}{vpn} && $self->{control}{vpn}->get_name, + #- FIXME: add MS_DNSx variables if DNS servers are specified + }); +} + +sub write_settings { + my ($self, $_o_net, $_o_modules_conf) = @_; + require network::network; + my $file = network::network::get_ifcfg_file($self->get_interface); + network::network::write_interface_settings($self->build_ifcfg_settings, $file); + network::network::write_hostname($self->{address}{hostname}) if $self->{address}{hostname}; + require network::shorewall; + network::shorewall::update_interfaces_list($self->get_interface); + network::network::reload_net_applet(); +} + +sub connect { + my ($self) = @_; + require network::tools; + network::tools::start_interface($self->get_interface, 0); +} + +sub disconnect { + my ($self) = @_; + require network::tools; + network::tools::stop_interface($self->get_interface, 0); +} + +sub setup_thirdparty { + my ($self, $in) = @_; + my $driver = $self->get_driver; + # FIXME: weird return code + $driver && $self->can('get_thirdparty_settings') or return 1; + require network::thirdparty; + $self->{thirdparty} = network::thirdparty::apply_settings($in, ref $self, $self->get_thirdparty_settings, $driver); + $self->{device} = $self->{thirdparty}{device} if $self->{thirdparty} && $self->{thirdparty}{device}; + $self->{thirdparty}; +} + +sub prepare_device { + my ($self) = @_; + my $driver = $self->get_driver; + if ($driver) { + require modules; + eval { modules::load($driver) }; + } +} + +#- status messages can be sent using mdv-network-event +sub get_status_message { + my ($self, $status) = @_; + my $interface = $self->get_interface; + { + link_up => N("Link detected on interface %s", $interface), + link_down => N("Link beat lost on interface %s", $interface), + }->{$status}; +} + +1; diff --git a/lib/network/connection/cable.pm b/lib/network/connection/cable.pm new file mode 100644 index 0000000..e74ac6a --- /dev/null +++ b/lib/network/connection/cable.pm @@ -0,0 +1,77 @@ +package network::connection::cable; + +use strict; +use common; + +use base qw(network::connection::ethernet); + +use strict; +use common; +use modules; +use detect_devices; + +sub get_type_name() { N("Cable") } +sub get_type_description() { N("Cable modem") } +sub get_type_icon() { 'cablemodem-24.png' } +sub get_metric { 20 } + +sub handles_ifcfg { + my ($_class, $_ifcfg) = @_; + 0; +} + +my $bpalogin_file = '/etc/bpalogin.conf'; + +sub guess_protocol { + my ($self) = @_; + $self->{protocol} = 'dhcp'; +} + +sub guess_access_settings { + my ($self) = @_; + $self->{access}{use_bpalogin} = -e $::prefix . $bpalogin_file; + if ($self->{access}{use_bpalogin}) { + foreach (cat_($::prefix . $bpalogin_file)) { + /^username (.*)/ and $self->{access}{login} = $1; + /^password (.*)/ and $self->{access}{password} = $1; + } + } +} + +sub get_access_settings { + my ($self) = @_; + my %auth = ( + 0 => N("None"), + 1 => N("Use BPALogin (needed for Telstra)"), + ); + [ + { label => N("Authentication"), type => "list", val => \$self->{access}{use_bpalogin}, + list => [ sort keys %auth ], format => sub { $auth{$_[0]} } }, + { label => N("Account Login (user name)"), val => \$self->{access}{login}, + disabled => sub { !$self->{access}{use_bpalogin} } }, + { label => N("Account Password"), val => \$self->{access}{password}, hidden => 1, + disabled => sub { !$self->{access}{use_bpalogin} } }, + ]; +} + +sub write_settings { + my ($self, $o_net, $o_modules_conf) = @_; + if ($self->{access}{use_bpalogin}) { + substInFile { + s/username\s+.*\n/username $self->{access}{login}\n/; + s/password\s+.*\n/password $self->{access}{password}\n/; + } $::prefix . $bpalogin_file; + } + services::set_status("bpalogin", $self->{access}{use_bpalogin}); + $self->SUPER::write_settings($o_net, $o_modules_conf); +} + +sub install_packages { + my ($self, $in) = @_; + if ($self->{access}{use_bpalogin}) { + $in->do_pkgs->ensure_is_installed('bpalogin', '/usr/sbin/bpalogin') or return; + } + $self->SUPER::install_packages($in); +} + +1; diff --git a/lib/network/connection/cellular.pm b/lib/network/connection/cellular.pm new file mode 100644 index 0000000..a9c0d78 --- /dev/null +++ b/lib/network/connection/cellular.pm @@ -0,0 +1,52 @@ +package network::connection::cellular; + +use base qw(network::connection::ppp); + +use strict; +use common; + +my $cellular_d = "/etc/sysconfig/network-scripts/cellular.d"; + +sub get_providers { + require network::connection::providers::cellular; + (\%network::connection::providers::cellular::data, '|'); +} + +sub get_cellular_settings_file { + my ($self) = @_; + my $network = $self->get_selected_network or return; + $::prefix . $cellular_d . '/' . $network->{name}; +} + +sub load_cellular_settings { + my ($self) = @_; + my $file = $self->get_cellular_settings_file or return; + -f $file && { getVarsFromSh($file) }; +} + +sub selected_network_is_configured { + my ($self) = @_; + defined($self->load_cellular_settings); +} + +sub write_cellular_settings { + my ($self) = @_; + my $file = $self->get_cellular_settings_file or return; + setVarsInShMode($file, 0600, { map { (uc($_) => $self->{access}{$_}) } qw(login password apn) }); +} + +sub guess_access_settings { + my ($self) = @_; + my $settings = $self->load_cellular_settings || {}; + $self->{access}{$_} = $settings->{uc($_)} || $self->{provider}{$_} foreach qw(login password apn); +} + +sub get_access_settings { + my ($self) = @_; + [ + { label => N("Access Point Name"), val => \$self->{access}{apn} }, + @{$self->SUPER::get_access_settings}, + ]; +} + +1; diff --git a/lib/network/connection/cellular_bluetooth.pm b/lib/network/connection/cellular_bluetooth.pm new file mode 100644 index 0000000..1457795 --- /dev/null +++ b/lib/network/connection/cellular_bluetooth.pm @@ -0,0 +1,94 @@ +package network::connection::cellular_bluetooth; + +use base qw(network::connection::cellular); + +use strict; +use common; + +my $rfcomm_dev_prefix = "/dev/rfcomm"; + +sub get_type_name { N("Bluetooth") } +sub get_type_description { N("Bluetooth Dial Up Networking") } +sub get_type_icon { 'bluetooth-24.png' } +sub get_devices { search_services('DUN') } +sub get_metric { 45 } +sub get_interface { "ppp0" } + +sub get_rfcomm_device { + my ($self) = @_; + $self->{rfcomm_device} ||= find { ! -e ($rfcomm_dev_prefix . $_) } 0 .. 99; +} + +sub get_tty_device { + my ($self) = @_; + $rfcomm_dev_prefix . $self->get_rfcomm_device; +} + +# http://www.hingston.demon.co.uk/mike/nokia6680.html +# http://kapsi.fi/~mcfrisk/linux_gprs.html +# GPRS specific commands http://www.phonestar.com.my/s_at_10.html + +sub search_services { + my ($service_type) = @_; + my (@services); + my $service = {}; + my ($key, $value); + my $push_service = sub { push @services, $service if exists $service->{class} }; + my $use_key = sub { $key = $_[0]; undef $value }; + foreach (run_program::rooted_get_stdout($::prefix, 'sdptool', 'search', $service_type)) { + if (/^Searching for $service_type on (.+) \.\.\.$/) { + $push_service->(); + $service = { addr => $1 }; + } elsif (/^Service Name:\s+(.*)$/) { + $service->{name} = $1; + } elsif (/^Service Provider:\s+(.*)$/) { + $service->{name} = $1; + } elsif (/^\s*Channel:\s*(\d+)$/) { + $service->{channel} = $1; + } elsif (/^Service Class ID List/) { + $use_key->('class'); + } else { + $value = chomp_($_); + } + if ($key && $value) { + $service->{$key} = $value; + $use_key->(undef); + } + } + $push_service->(); + my %names; + foreach (@services) { + $names{$_->{addr}} ||= chomp_(run_program::rooted_get_stdout($::prefix, 'hcitool', 'name', $_->{addr})); + $_->{description} = $names{$_->{addr}}; + } + @services; +} + +sub write_settings { + my ($self) = @_; + + $self->write_cellular_settings; + + my $dev = $self->get_rfcomm_device; + output("$::prefix/etc/bluetooth/rfcomm.conf", qq( +rfcomm$dev { + bind yes; + device $self->{device}{addr}; + channel $self->{device}{channel}; + comment "Dial-up networking"; +} +)); + + my $cid = 1; + $self->{access}{at_commands} = [ qq(AT+CGDCONT=$cid,"IP","$self->{access}{apn}") ]; + $self->{access}{dial_number} = "*99***$cid#"; + + $self->SUPER::write_settings; +} + +sub prepare_connection { + my ($self) = @_; + run_program::rooted_get_stdout($::prefix, 'rfcomm', 'bind', $self->get_rfcomm_device); +} + +1; diff --git a/lib/network/connection/cellular_card.pm b/lib/network/connection/cellular_card.pm new file mode 100644 index 0000000..9132f49 --- /dev/null +++ b/lib/network/connection/cellular_card.pm @@ -0,0 +1,180 @@ +package network::connection::cellular_card; + +use base qw(network::connection::cellular); + +use strict; +use common; + +sub get_type_name() { N("GPRS/Edge/3G") } +sub get_type_icon() { 'cellular-24.png' } +sub get_devices() { + require detect_devices; + my @maybe_usbserial_modules = ('usbserial_generic', 'unknown'); + my @serial = grep { $_->{description} =~ /GPRS|EDGE|3G|UMTS|H.DPA/i } detect_devices::matching_driver('serial_cs', 'usbserial', @maybe_usbserial_modules); + member($_->{driver}, @maybe_usbserial_modules) and $_->{driver} = 'usbserial' foreach @serial; + @serial, detect_devices::probe_category('network/cellular'); +} +sub get_metric { 40 } +sub get_interface() { "ppp0" } + +sub get_packages { 'comgt', 'ppp' } + +my @thirdparty_settings = ( + { + name => 'nozomi', + description => 'Option GlobeTrotter 3G/EDGE and FUSION+', + url => 'http://www.pharscape.org/', + kernel_module => 1, + }, +); + +sub get_thirdparty_settings() { + \@thirdparty_settings; +} + +sub guess_hardware_settings { + my ($self) = @_; + $self->{hardware}{pin} ||= chomp_(cat_("/etc/sysconfig/network-scripts/pin-" . $self->get_interface)); +} + +sub get_tty_device { + my ($self) = @_; + $self->{device}{device} ? + "/dev/" . $self->{device}{device} : + $self->get_driver eq "nozomi" ? + "/dev/noz0" : + "/dev/ttyUSB0"; +} + +sub network_scan_is_slow() { 1 } + +sub get_networks { + my ($self) = @_; + my $cmd = "gcom -d " . $self->get_tty_device; + my ($network, $state) = `$cmd reg` =~ /^Registered on \w+ network: "(.*)",(\d+)$/m; + my ($strength) = `$cmd sig` =~ /^Signal Quality:\s+(\d+),\d+$/; + $self->{networks} = $network && { + $network => { + name => $network, + signal_strength => $strength * 5, + current => $state == 2, + } + }; +} + +sub get_hardware_settings { + my ($self) = @_; + [ { label => N("PIN number"), val => \$self->{hardware}{pin}, hidden => 1 } ]; +} + +sub get_peer_default_options { + my ($self) = @_; + $self->SUPER::get_peer_default_options, + "noccp", # disable CCP to avoid warning messages + "debug"; +} + +sub build_peer { + my ($self) = @_; + $self->SUPER::build_peer; + #- don't run gcom for now, it hangs on ttyUSB0 devices when run from pppd + #- $self->{access}{peer}->{init} = "gcom -d $dev < $pin_file" +} + +sub write_settings { + my ($self) = @_; + + $self->write_cellular_settings; + + my $interface = $self->get_interface; + my $pin_file = "/etc/sysconfig/network-scripts/pin-$interface"; + + output_with_perm($pin_file, 0600, $self->{hardware}{pin} . "\n"); + + my $cid = 3; + $self->{access}{at_commands} = [ + "AT+CPIN?", + # Set +CGEE to 2 + "AT+CMEE=2", + qq(AT+CGDCONT=$cid,"IP","$self->{access}{apn}"), + # Setup +CGEQREG (QoS, don't set it for now) + # qq(AT+CGEQREQ=3,3,64,384,0,0,2,0,"0E0","0E0",3,0,0), + # Attached to network, will return 1 + "AT+CGATT?", + ]; + $self->{access}{dial_number} = "*99***$cid#"; + + $self->SUPER::write_settings; +} + +sub prepare_device { + my ($self) = @_; + + my $driver = $self->get_driver; + require modules; + my $modules_conf = !is_empty_hash_ref($::o) ? $::o->{modules_conf} : modules::any_conf->read; + modules::load_and_configure($modules_conf, $driver, + if_($driver eq 'usbserial', join( + ' ', + "vendor=0x" . sprintf("%4x", $self->{device}{vendor}), + "product=0x" . sprintf("%4x", $self->{device}{id})))); + $modules_conf->write if !ref $::o; + sleep 2 if $driver eq 'usbserial'; +} + +sub check_device { + my ($self) = @_; + + my $dev = $self->get_tty_device; + if (! -e $dev) { + $self->{device}{error} = N("Unable to open device %s", $dev); + return; + } + + 1; +} + +sub check_hardware { + my ($self) = @_; + + my $device_ready = 0; + + require IPC::Open2; + require IO::Select; + require c; + use POSIX qw(:errno_h); + + my $pid = IPC::Open2::open2(my $cmd_out, my $cmd_in, "gcom", "-d", $self->get_tty_device); + common::nonblock($cmd_out); + my $selector = IO::Select->new($cmd_out); + while ($selector->can_read) { + local $_; + my $rv = sysread($cmd_out, $_, 512); + $rv == 0 and $selector->remove($cmd_out); + if (/^\*\*\*SIM ERROR\*\*\*/m) { + $self->{hardware}{error} = N("Please check that your SIM card is inserted."); + last; + } elsif (/^Enter PIN number:/m) { + $self->{hardware}{pin} or last; + print $cmd_in $self->{hardware}{pin} . "\n"; + } elsif (/^ERROR entering PIN/m) { + $self->{hardware}{error} = N("You entered a wrong PIN code. +Entering the wrong PIN code multiple times may lock your SIM card!"); + last; + } elsif (/^Waiting for Registration/m) { + #- the card seems to be resetted if gcom is killed right here, wait a bit + sleep 1; + #- don't wait the full scan + $device_ready = 1; + last; + } + } + kill 'TERM', $pid; + close($cmd_out); + close($cmd_in); + waitpid($pid, c::WNOHANG()); + + $device_ready; +} + +1; diff --git a/lib/network/connection/dvb.pm b/lib/network/connection/dvb.pm new file mode 100644 index 0000000..3364886 --- /dev/null +++ b/lib/network/connection/dvb.pm @@ -0,0 +1,73 @@ +package network::connection::dvb; + +use strict; +use common; + +use base qw(network::connection::ethernet); + +use strict; +use common; +use modules; + +sub get_type_name() { N("DVB") } +sub get_type_description() { N("Satellite (DVB)") } +sub get_type_icon() { 'dvb-24.png' } + +sub get_devices() { + require detect_devices; + detect_devices::probe_category("multimedia/dvb"); +} + +sub get_metric { 15 } + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + exists $ifcfg->{DVB_ADAPTER_ID}; +} + +sub get_interface { + my ($self) = @_; + defined $self->{hardware}{adapter_id} && defined $self->{hardware}{network_demux} or return "dvb"; + 'dvb' . $self->{hardware}{adapter_id} . '_' . $self->{hardware}{network_demux}; +} + +sub get_dvb_device { + find { sysopen(undef, $_, c::O_RDWR() | c::O_NONBLOCK()) } glob("/dev/dvb/adapter*/net*"); +} + +sub load_interface_settings { + my ($self) = @_; + $self->guess_hardware_settings; #- so that matching interface settings can be loaded + $self->network::connection::load_interface_settings; + $self->{hardware}{adapter_id} = $self->{ifcfg}{DVB_ADAPTER_ID}; + $self->{hardware}{network_demux} = $self->{ifcfg}{DVB_NETWORK_DEMUX}; + $self->{hardware}{network_pid} = $self->{ifcfg}{DVB_NETWORK_PID}; +} + +sub guess_hardware_settings { + my ($self) = @_; + my $device = get_dvb_device() or return; + ($self->{hardware}{adapter_id}, $self->{hardware}{network_demux}) = $device =~ m,/dev/dvb/adapter(\d+)/net(\d+),; +} + +sub get_hardware_settings { + my ($self) = @_; + [ + { label => N("Adapter card"), val => \$self->{hardware}{adapter_id} }, + { label => N("Net demux"), val => \$self->{hardware}{network_demux} }, + { label => N("PID"), val => \$self->{hardware}{network_pid} }, + ]; +} + +sub build_ifcfg_settings { + my ($self) = @_; + my $settings = { + DVB_ADAPTER_ID => qq("$self->{hardware}{adapter_id}"), + DVB_NETWORK_DEMUX => qq("$self->{hardware}{network_demux}"), + DVB_NETWORK_PID => qq("$self->{hardware}{network_pid}"), + MII_NOT_SUPPORTED => "yes", + }; + $self->SUPER::build_ifcfg_settings($settings); +} + +1; diff --git a/lib/network/connection/ethernet.pm b/lib/network/connection/ethernet.pm new file mode 100644 index 0000000..39752f5 --- /dev/null +++ b/lib/network/connection/ethernet.pm @@ -0,0 +1,512 @@ +package network::connection::ethernet; # $Id: ethernet.pm 147431 2007-03-21 17:06:09Z blino $ + +use base qw(network::connection); + +use strict; +use common; + +our @dhcp_clients = qw(dhclient dhcpcd pump dhcpxd); + +sub get_type_name() { N("Ethernet") } +sub get_type_icon() { 'ethernet-24.png' } + +sub get_devices() { + #require list_modules; + #- FIXME: try to use list_modules::ethernet_categories() (but remove wireless stuff) + require detect_devices; + my @devices = detect_devices::probe_category('network/main|gigabit|pcmcia|tokenring|usb|firewire'); + my @lan = grep { detect_devices::is_lan_interface($_) && !detect_devices::is_wireless_interface($_) } detect_devices::get_all_net_devices(); + @devices, get_unlisted_devices(\@lan, \@devices); +} + +sub get_unlisted_devices { + my ($interfaces, $listed_devices) = @_; + my @unlisted_interfaces = sort(difference2($interfaces, [ map { device_to_interface($_) } @$listed_devices ])); + map { interface_to_device($_) || +{ description => $_, interface => $_ } } @unlisted_interfaces; +} + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + require detect_devices; + detect_devices::is_lan_interface($ifcfg->{DEVICE}); +} + +sub is_gigabit { + my ($self) = @_; + require list_modules; + member($self->get_driver, list_modules::category2modules('network/gigabit')); +} + +sub get_metric { + my ($self) = @_; + $self->is_gigabit ? 5 : 10; +} + +sub get_interface { + my ($self) = @_; + $self->{device}{interface} || device_to_interface($self->{device}); +} + +sub check_device { + my ($self) = @_; + if (!$self->get_interface) { + $self->{device}{error} = N("Unable to find network interface for selected device (using %s driver).", $self->get_driver); + return 0; + } + return 1; +} + +sub get_protocols() { + { + static => N("Manual configuration"), + dhcp => N("Automatic IP (BOOTP/DHCP)"), + }; +} + +sub load_interface_settings { + my ($self) = @_; + + $self->network::connection::load_interface_settings; + + $self->{protocol} = $self->{ifcfg}{BOOTPROTO}; + + $self->{address}{needhostname} = $self->get_ifcfg_bool('NEEDHOSTNAME'); + $self->{address}{peerdns} = $self->get_ifcfg_bool('PEERDNS'); + $self->{address}{peeryp} = $self->get_ifcfg_bool('PEERYP'); + $self->{address}{peerntpd} = $self->get_ifcfg_bool('PEERNTPD'); + + $self->{address}{dhcp_client} = $self->{ifcfg}{DHCP_CLIENT}; + $self->{address}{dhcp_hostname} = $self->{ifcfg}{DHCP_HOSTNAME}; + $self->{address}{dhcp_timeout} = $self->{ifcfg}{DHCP_TIMEOUT}; + $self->{address}{ip_address} = $self->{ifcfg}{IPADDR}; + $self->{address}{netmask} = $self->{ifcfg}{NETMASK}; + $self->{address}{gateway} = $self->{ifcfg}{GATEWAY}; + $self->{address}{dns1} = $self->{ifcfg}{DNS1} || $self->{ifcfg}{MS_DNS1}; + $self->{address}{dns2} = $self->{ifcfg}{DNS2} || $self->{ifcfg}{MS_DNS2}; + $self->{address}{domain} = $self->{ifcfg}{DOMAIN}; + + my $blacklist_ifplugd = $self->get_ifcfg_bool('MII_NOT_SUPPORTED'); + $self->{control}{use_ifplugd} = !$blacklist_ifplugd if defined $blacklist_ifplugd; + $self->{control}{ipv6_tunnel} = $self->get_ifcfg_bool('IPV6TO4INIT'); +} + +sub guess_protocol { + my ($self) = @_; + $self->{protocol} ||= 'dhcp'; +} + +sub guess_address_settings { + my ($self) = @_; + $self->{address}{dhcp_client} ||= find { -x "$::prefix/sbin/$_" } @dhcp_clients; + $self->{address}{peerdns} = 1 if !defined $self->{address}{peerdns}; + $self->{address}{peeryp} = 1 if !defined $self->{address}{peeryp}; + $self->supplement_address_settings; +} + +sub supplement_address_settings { + my ($self) = @_; + if ($self->{protocol} eq 'static' && network::network::is_ip($self->{address}{ip_address})) { + require network::network; + $self->{address}{netmask} ||= network::network::netmask($self->{address}{ip_address}); + $self->{address}{gateway} ||= network::network::gateway($self->{address}{ip_address}); + $self->{address}{dns1} ||= network::network::dns($self->{address}{ip_address}); + } +} + +sub get_address_settings_label { N("IP settings") } + +sub get_address_settings { + my ($self, $o_show_all) = @_; + my $auto_dns = sub { $self->{protocol} eq 'dhcp' && $self->{address}{peerdns} }; + my $not_static = sub { $self->{protocol} ne 'static' }; + my $not_dhcp = sub { $self->{protocol} ne 'dhcp' }; + [ + if_($self->{protocol} eq 'static' || $o_show_all, + { label => N("IP address"), val => \$self->{address}{ip_address}, disabled => $not_static, + focus_out => sub { + $self->supplement_address_settings if $self->can('supplement_address_settings'); + }, + help => N("Please enter the IP configuration for this machine. +Each item should be entered as an IP address in dotted-decimal +notation (for example, 1.2.3.4).") }, + { label => N("Netmask"), val => \$self->{address}{netmask}, disabled => $not_static }, + { label => N("Gateway"), val => \$self->{address}{gateway}, disabled => $not_static }, + ), + if_($self->{protocol} eq 'dhcp' || $o_show_all, + { text => N("Get DNS servers from DHCP"), val => \$self->{address}{peerdns}, type => "bool", disabled => $not_dhcp }, + ), + { label => N("DNS server 1"), val => \$self->{address}{dns1}, disabled => $auto_dns }, + { label => N("DNS server 2"), val => \$self->{address}{dns2}, disabled => $auto_dns }, + { label => N("Search domain"), val => \$self->{address}{domain}, disabled => $auto_dns, advanced => 1, + help => N("By default search domain will be set from the fully-qualified host name") }, + if_($self->{protocol} eq 'dhcp', + { label => N("DHCP client"), val => \$self->{address}{dhcp_client}, list => \@dhcp_clients, advanced => 1 }, + { label => N("DHCP timeout (in seconds)"), val => \$self->{address}{dhcp_timeout}, advanced => 1 }, + { text => N("Get YP servers from DHCP"), val => \$self->{address}{peeryp}, type => "bool", advanced => 1 }, + { text => N("Get NTPD servers from DHCP"), val => \$self->{address}{peerntpd}, type => "bool", advanced => 1 }, + { label => N("DHCP host name"), val => \$self->{address}{dhcp_hostname}, advanced => 1 }, + #- FIXME: install zcip if not checked + if_(0, { text => N("Do not fallback to Zeroconf (169.254.0.0 network)"), type => "bool", val => \$self->{address}{skip_zeroconf}, advanced => 1 }), + ), + ]; +} + +sub check_address_settings { + my ($self, $net) = @_; + + if ($self->{protocol} eq 'static') { + require network::network; + if (!network::network::is_ip($self->{address}{ip_address})) { + $self->{address}{error}{message} = N("IP address should be in format 1.2.3.4"); + $self->{address}{error}{field} = \$self->{address}{ip_address}; + return 0; + } + if (!network::network::is_ip($self->{address}{netmask})) { + $self->{address}{error}{message} = N("Netmask should be in format 255.255.224.0"); + $self->{address}{error}{field} = \$self->{address}{netmask}; + return 0; + } + if (network::network::is_ip_forbidden($self->{address}{ip_address})) { + $self->{address}{error}{message} = N("Warning: IP address %s is usually reserved!", $self->{address}{ip_address}); + $self->{address}{error}{field} = \$self->{address}{ip_address}; + return 0; + } + #- test if IP address is already used + if (find { text2bool($_->{ONBOOT}) && $_->{DEVICE} ne $self->get_interface && $_->{IPADDR} eq $self->{address}{ip_address} } values %{$net->{ifcfg}}) { + $self->{address}{error}{message} = N("%s already in use\n", $self->{address}{ip_address}); + $self->{address}{error}{field} = \$self->{address}{ip_address}; + return 0; + } + } + + return 1; +} + +sub guess_hostname_settings { + my ($self) = @_; + $self->{address}{needhostname} = 0 if !defined $self->{address}{needhostname}; + if (!defined $self->{address}{hostname}) { + require network::network; + my $network = network::network::read_conf($::prefix . $network::network::network_file); + $self->{address}{hostname} = $network->{HOSTNAME}; + } +} + +sub get_hostname_settings { + my ($self) = @_; + my $auto_hostname = sub { $self->{protocol} eq 'dhcp' && $self->{address}{needhostname} }; + [ + if_($self->{protocol} eq 'dhcp', + { text => N("Assign host name from DHCP address"), val => \$self->{address}{needhostname}, type => "bool" }, + ), + { label => N("Host name"), val => \$self->{address}{hostname}, disabled => $auto_hostname }, + ]; +} + +sub guess_control_settings { + my ($self) = @_; + + $self->network::connection::guess_control_settings($self); + + $self->{control}{onboot} = 1 if !defined $self->{control}{onboot}; + $self->{control}{use_ifplugd} = !is_ifplugd_blacklisted($self->get_driver) + if !defined $self->{control}{use_ifplugd}; +} + +sub get_control_settings { + my ($self) = @_; + [ + @{$self->network::connection::get_control_settings}, + { text => N("Network Hotplugging"), val => \$self->{control}{use_ifplugd}, type => "bool", + #- FIXME: force ifplugd if wireless roaming is enabled + disabled => sub { $self->{control}{force_ifplugd} }, advanced => 1, }, + #- FIXME: $need_network_restart = $ipv6_tunnel ^ text2bool($ethntf->{IPV6TO4INIT}); + { text => N("Enable IPv6 to IPv4 tunnel"), val => \$self->{control}{ipv6_tunnel}, type => "bool", advanced => 1 }, + ]; +} + +sub install_packages { + my ($self, $in) = @_; + if ($self->{protocol} eq 'dhcp') { + install_dhcp_client($in, $self->{address}{dhcp_client}) or return; + } + 1; +} + +sub build_ifcfg_settings { + my ($self, $o_options) = @_; + my $settings = put_in_hash($o_options, { + BOOTPROTO => $self->{protocol}, + IPADDR => $self->{address}{ip_address}, + GATEWAY => $self->{address}{gateway}, + NETMASK => $self->{address}{netmask}, + NEEDHOSTNAME => bool2yesno($self->{address}{needhostname}), + PEERYP => bool2yesno($self->{address}{peeryp}), + PEERDNS => bool2yesno($self->{address}{peerdns}), + RESOLV_MODS => bool2yesno($self->{address}{dns1} || $self->{address}{dns2}), + PEERNTPD => bool2yesno($self->{address}{peerntpd}), + DHCP_CLIENT => $self->{address}{dhcp_client}, + DHCP_HOSTNAME => $self->{address}{dhcp_hostname}, + DHCP_TIMEOUT => $self->{address}{dhcp_timeout}, + MII_NOT_SUPPORTED => bool2yesno(!$self->{control}{use_ifplugd}), + IPV6INIT => bool2yesno($self->{control}{ipv6_tunnel}), + IPV6TO4INIT => bool2yesno($self->{control}{ipv6_tunnel}), + DNS1 => $self->{address}{dns1}, + DNS2 => $self->{address}{dns2}, + DOMAIN => $self->{address}{domain}, + LINK_DETECTION_DELAY => $self->get_link_detection_delay, + }); + $self->network::connection::build_ifcfg_settings($settings); +} + +sub write_settings { + my ($self, $o_net, $o_modules_conf) = @_; + $o_modules_conf->set_alias($self->get_interface, $self->get_driver) if $o_modules_conf; + $self->SUPER::write_settings($o_net, $o_modules_conf); +} + +sub get_status_message { + my ($self, $status) = @_; + my $interface = $self->get_interface; + { + link_up => N("Link beat detected on interface %s", $interface), + link_down => N("Link beat lost on interface %s", $interface), + map { ( + "$_->[0]_request" => N("Requesting a network address on interface %s (%s protocol)...", $interface, $_->[1]), + "$_->[0]_success" => N("Got a network address on interface %s (%s protocol)", $interface, $_->[1]), + "$_->[0]_failure" => N("Failed to get a network address on interface %s (%s protocol)", $interface, $_->[1]), + ) } ([ 'dhcp', 'DHCP' ], [ 'zcip', 'ZeroConf' ]), + }->{$status} || $self->network::connection::get_status_message($status); +} + +use c; +use detect_devices; +use common; +use run_program; + +sub install_dhcp_client { + my ($in, $client) = @_; + my %packages = ( + "dhclient" => "dhcp-client", + ); + #- use default dhcp client if none is provided + $client ||= $dhcp_clients[0]; + $client = $packages{$client} if exists $packages{$client}; + $in->do_pkgs->ensure_is_installed($client, undef, 1); +} + +my @hwaddr_fields = qw(pci_domain pci_bus pci_device pci_function); + +sub are_same_HwIDs { + my ($device1, $device2) = @_; + every { $device1->{$_} == $device2->{$_} } @hwaddr_fields; +} + +sub parse_hwaddr { + my ($hw_addr) = @_; + return if !$hw_addr; + my %device; + @device{@hwaddr_fields} = map { hex($_) } ($hw_addr =~ /([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)\.([0-9a-f]+)/); + (every { defined $_ } keys %device) ? \%device : undef; +} + +sub mapIntfToDevice { + my ($interface) = @_; + my $hw_addr = c::getHwIDs($interface); + return {} if $hw_addr =~ /^usb/; + my $device = parse_hwaddr($hw_addr); + $device ? grep { are_same_HwIDs($_, $device) } detect_devices::probeall__real() : {}; +} + +sub device_matches_interface_HwIDs { + my ($device, $interface) = @_; + my $hw_addr = c::getHwIDs($interface); + $hw_addr =~ /^usb/ and return; + my ($device2) = parse_hwaddr($hw_addr); + return if !$device2; + are_same_HwIDs($device, $device2); +} + +sub get_interface_sysfs_path { + my ($interface) = @_; + my $dev_path = "/sys/class/net/$interface/device"; + my $bus = detect_devices::get_sysfs_field_from_link($dev_path, 'bus'); + if ($bus eq 'ieee1394') { + my $child = first(glob("$dev_path/host_id/*-*")); + $dev_path = $child if $child; + } + $dev_path; +} + +sub get_interface_ids { + my ($interface) = @_; + detect_devices::get_ids_from_sysfs_device(get_interface_sysfs_path($interface)); +} + +sub device_matches_interface { + my ($device, $interface) = @_; + detect_devices::device_matches_sysfs_ids($device, get_interface_ids($interface)); +} + +sub device_to_interface { + my ($device) = @_; + my @all_interfaces = detect_devices::get_net_interfaces(); + find { + device_matches_interface_HwIDs($device, $_) || + device_matches_interface($device, $_); + } @all_interfaces; +} + +sub interface_to_device { + my ($interface) = @_; + my $sysfs_ids = get_interface_ids($interface); + find { detect_devices::device_matches_sysfs_ids($_, $sysfs_ids) } detect_devices::probeall__real(); +} + +sub interface_to_driver { + my ($interface) = @_; + my $dev_path = get_interface_sysfs_path($interface); + #- FIXME: use $bus and move in get_interface_sysfs_path if possible + my $child = -f "$dev_path/idVendor" && first(glob("$dev_path/*-*:*.*")); + $dev_path = $child if -f "$child/driver"; + detect_devices::get_sysfs_field_from_link($dev_path, 'driver'); +} + +# return list of [ intf_name, module, device_description ] tuples such as: +# [ "eth0", "3c59x", "3Com Corporation|3c905C-TX [Fast Etherlink]" ] +# +# this function try several method in order to get interface's driver and description in order to support both: +# - hotplug managed devices (USB, firewire) +# - special interfaces (IP aliasing, VLAN) +sub get_eth_cards { + my ($modules_conf) = @_; + my @all_cards = detect_devices::get_lan_interfaces(); + + my @devs = detect_devices::pcmcia_probe(); + my $saved_driver; + # compute device description and return (interface, driver, description) tuples: + return map { + my $interface = $_; + my $description; + # 1) get interface's driver through ETHTOOL ioctl: + my ($a, $detected_through_ethtool); + $a = c::getNetDriver($interface); + if ($a) { + $detected_through_ethtool = 1; + } else { + # 2) get interface's driver through module aliases: + $a = $modules_conf->get_alias($interface); + } + + # workaround buggy drivers that returns a bogus driver name for the GDRVINFO command of the ETHTOOL ioctl: + my %fixes = ( + "p80211_prism2_cs" => 'prism2_cs', + "p80211_prism2_pci" => 'prism2_pci', + "p80211_prism2_usb" => 'prism2_usb', + "ip1394" => "eth1394", + "DL2K" => "dl2k", + "orinoco" => undef, #- should be orinoco_{cs,nortel,pci,plx,tmd} + "hostap" => undef, #- should be hostap_{cs,pci,plx} + ); + if (exists $fixes{$a}) { + $a = $fixes{$a}; + $a or undef $detected_through_ethtool; + } + + # 3) try to match a PCMCIA device for device description: + if (my $b = find { $_->{device} eq $interface } @devs) { # PCMCIA case + $a = $b->{driver}; + $description = $b->{description}; + } else { + # 4) try to lookup a device by hardware address for device description: + # maybe should have we try sysfs first for robustness? + ($description) = (mapIntfToDevice($interface))[0]->{description}; + } + # 5) try to match a device through sysfs for driver & device description: + # (eg: ipw2100 driver for intel centrino do not support ETHTOOL) + if (!$description || !$a) { + my $drv = interface_to_driver($interface); + $a = $drv if $drv && !$detected_through_ethtool; + my $card = interface_to_device($interface); + $description ||= $card->{description} if $card; + } + # 6) try to match a device by driver for device description: + # (eg: madwifi, ndiswrapper, ...) + if (!$description) { + my @cards = grep { $_->{driver} eq ($a || $saved_driver) } detect_devices::probeall__real(); + $description = $cards[0]{description} if @cards == 1; + } + $a and $saved_driver = $a; # handle multiple cards managed by the same driver + [ $interface, $saved_driver, if_($description, $description) ]; + } @all_cards; +} + +sub get_eth_cards_names { + my (@all_cards) = @_; + map { $_->[0] => join(': ', $_->[0], $_->[2]) } @all_cards; +} + +#- returns (link_type, mac_address) +sub get_eth_card_mac_address { + my ($intf) = @_; + #- don't look for 6 bytes addresses only because of various non-standard MAC addresses + `$::prefix/sbin/ip -o link show $intf 2>/dev/null` =~ m|.*link/(\S+)\s((?:[0-9a-f]{2}:?)+)\s|; +} + +#- write interfaces MAC address in iftab +sub update_iftab() { + #- skip aliases interfaces + foreach my $intf (grep { !/:\d+$/ } detect_devices::get_lan_interfaces()) { + my ($link_type, $mac_address) = get_eth_card_mac_address($intf) or next; + #- do not write zeroed MAC addresses in iftab, it confuses ifrename + $mac_address =~ /^[0:]+$/ and next; + # ifrename supports alsa IEEE1394, EUI64 and IRDA + member($link_type, 'ether', 'ieee1394', 'irda', '[27]') or next; + substInFile { + s/^$intf\s+.*\n//; + s/^.*\s+$mac_address\n//; + $_ .= qq($intf mac $mac_address\n) if eof; + } "$::prefix/etc/iftab"; + } +} + +sub update_udev_net_config() { + my $lib = arch() =~ /x86_64/ ? "lib64" : "lib"; + my $net_name_helper = "/$lib/udev/net_name_helper"; + my $udev_net_config = "/etc/udev/rules.d/61-net_config.rules"; + my @old_config = cat_($udev_net_config); + #- skip aliases and vlan interfaces + foreach my $intf (grep { !/[:.]\d+$/ } detect_devices::get_lan_interfaces()) { + (undef, my $mac_address) = get_eth_card_mac_address($intf) or next; + #- do not write zeroed MAC addresses + $mac_address =~ /^[0:]+$/ and next; + #- skip already configured addresses + any { !/^\s*#/ && /"$mac_address"/ } @old_config and next; + local $ENV{INTERFACE} = $intf; + local $ENV{SUBSYSTEM} = 'net'; + run_program::rooted($::prefix, $net_name_helper, '>', '/dev/null', $mac_address); + } +} + +# automatic net aliases configuration +sub configure_eth_aliases { + my ($modules_conf) = @_; + foreach my $card (get_eth_cards($modules_conf)) { + $modules_conf->set_alias($card->[0], $card->[1]); + } + $::isStandalone and $modules_conf->write; + update_iftab(); + update_udev_net_config(); +} + +sub get_link_detection_delay { + my ($self) = @_; + member($self->get_driver, qw(forcedeth r8169 skge sky2 tg3)) && 6; +} + +sub is_ifplugd_blacklisted { + my ($module) = @_; + !$module || member($module, qw(via-velocity)); +} + +1; diff --git a/lib/network/isdn.pm b/lib/network/connection/isdn.pm index 740741b..4b85d1d 100644 --- a/lib/network/isdn.pm +++ b/lib/network/connection/isdn.pm @@ -1,18 +1,40 @@ -package network::isdn; # $Id$ +package network::connection::isdn; + +use base qw(network::connection); use strict; -use network::isdn_consts; use common; + +sub get_type_name { N("ISDN") } +sub get_type_icon { 'isdn-24.png' } + +sub get_devices { + require modules; + #- FIXME: module alias should be written when config is written only + @{detect_backend(modules::any_conf->read)}; +} +sub get_metric { 30 } + +use network::connection::isdn::consts; use modules; use run_program; use log; use network::tools; use services; - -sub write_config { +sub apply_config { my ($in, $isdn) = @_; - $in->do_pkgs->install('isdn4net', if_($isdn->{speed} =~ /128/, 'ibod'), 'isdn4k-utils'); + + $isdn = find_capi_card($isdn) if $isdn->{driver} eq "capidrv"; + unload_connection($isdn); + install_packages($isdn, $in); + write_settings($isdn); + write_capi_conf($isdn) if $isdn->{driver} eq "capidrv"; + prepare_connection($isdn); +} + +sub write_settings { + my ($isdn) = @_; output_with_perm("$::prefix/etc/isdn/profile/link/myisp", 0600, qq( @@ -44,33 +66,13 @@ usepeerdns defaultroute "; - services::stop("isdn4linux"); #- to be stopped before capi is loaded - if ($isdn->{driver} eq "capidrv") { - setup_capi_conf($in, get_capi_card($in, $isdn)); - services::enable('capi4linux'); - } else { - services::disable('capi4linux'); - } - services::enable('isdn4linux'); - network::tools::write_secret_backend($isdn->{login}, $isdn->{passwd}); 1; } - -sub setup_capi_conf { - my ($in, $capi_card) = @_; - - $in->do_pkgs->ensure_is_installed('isdn4k-utils', "/etc/rc.d/init.d/capi4linux"); #- capi4linux service - is_module_installed($capi_card->{driver}) or $in->do_pkgs->install(@{$capi_card->{packages}}); - if ($capi_card->{firmware} && ! -f "$::prefix/usr/lib/isdn/$capi_card->{firmware}") { - $in->do_pkgs->install("$capi_card->{driver}-firmware"); - } - - #- stop capi4linux before new config is written so that it can unload the driver - services::stop("capi4linux"); - +sub write_capi_conf { + my ($capi_card) = @_; my $capi_conf; my $firmware = $capi_card->{firmware} || '-'; if ($capi_card->{driver} eq "fcclassic") { @@ -80,9 +82,43 @@ sub setup_capi_conf { } else { $capi_conf = "$capi_card->{driver} $firmware - - - - -\n"; } + output("$::prefix/etc/capi.conf", $capi_conf); } +sub unload_connection { + my ($isdn) = @_; + require services; + services::stop("isdn4linux"); #- to be stopped before capi is loaded + if ($isdn->{driver} eq "capidrv") { + #- stop capi4linux before new config is written so that it can unload the driver + services::stop("capi4linux"); + } +} + +sub install_packages { + my ($isdn, $in) = @_; + + $in->do_pkgs->install( + 'isdn4k-utils', + $isdn->{driver} eq "capidrv" ? + (if_(!modules::module_is_available($isdn->{driver}), @{$isdn->{packages}}), + if_($isdn->{firmware} && ! -f "$::prefix/usr/lib/isdn/$isdn->{firmware}", "$isdn->{driver}-firmware")) + : + ('isdn4net', if_($isdn->{speed} =~ /128/, 'ibod')) + ); +} + +sub prepare_connection { + my ($isdn) = @_; + if ($isdn->{driver} eq "capidrv") { + services::enable('capi4linux'); + } else { + services::disable('capi4linux'); + } + services::enable('isdn4linux'); +} + sub read_config { my ($isdn) = @_; @@ -145,7 +181,7 @@ sub detect_backend { } $c->{options} =~ /protocol=(\d)/ and $isdn->{protocol} = $1; push @isdn, $isdn; - } modules::probe_category('network/isdn'); + } detect_devices::probe_category('network/isdn'); \@isdn; } @@ -168,21 +204,20 @@ sub get_cards() { } -sub is_module_installed { - my ($driver) = @_; - find { m!/\Q$driver\E\.k?o! } cat_($::prefix . '/lib/modules/' . c::kernel_version() . '/modules.dep'); +sub find_capi_card { + my ($isdn) = @_; + find { + hex($isdn->{vendor}) == $_->{vendor} && hex($isdn->{id}) == $_->{id}; + } @isdn_capi; } - sub get_capi_card { my ($in, $isdn) = @_; - my $capi_card = find { - hex($isdn->{vendor}) == $_->{vendor} && hex($isdn->{id}) == $_->{id}; - } @isdn_capi or return; + my $capi_card = find_capi_card($isdn) or return; #- check if the capi driver is available - unless (is_module_installed($capi_card->{driver}) || ($capi_card->{packages} = $in->do_pkgs->check_kernel_module_packages("$capi_card->{driver}-kernel"))) { + unless (modules::module_is_available($capi_card->{driver}) || ($capi_card->{packages} = $in->do_pkgs->check_kernel_module_packages($capi_card->{driver}))) { log::explanations("a capi driver ($capi_card->{driver}) exists to replace $isdn->{driver}, but it is not installed and no packages provide it"); return; } diff --git a/lib/network/isdn_consts.pm b/lib/network/connection/isdn/consts.pm index b2361fe..a53ddbe 100644 --- a/lib/network/isdn_consts.pm +++ b/lib/network/connection/isdn/consts.pm @@ -1,4 +1,4 @@ -package network::isdn_consts; # $Id$ +package network::connection::isdn::consts; # $Id: consts.pm 54070 2006-08-07 17:34:38Z blino $ use vars qw(@ISA @EXPORT); @ISA = qw(Exporter); @EXPORT = qw(@isdndata @isdn_capi); diff --git a/lib/network/connection/pots.pm b/lib/network/connection/pots.pm new file mode 100644 index 0000000..be7bf9f --- /dev/null +++ b/lib/network/connection/pots.pm @@ -0,0 +1,133 @@ +package network::connection::pots; + +use base qw(network::connection::ppp); + +use strict; +use common; + +sub get_type_name { + #-PO: POTS means "Plain old telephone service" + N("POTS"); +} +sub get_type_description { + #-PO: POTS means "Plain old telephone service" + #-PO: remove it if it doesn't have an equivalent in your language + #-PO: for example, in French, it can be translated as "RTC" + N("Analog telephone modem (POTS)"); +} +sub get_type_icon { 'potsmodem-24.png' } +sub get_metric { 50 } + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + $ifcfg->{DEVICE} =~ /^ppp/ && exists $ifcfg->{MODEMPORT}; +} + +sub get_devices { + require detect_devices; + require modules; + #- FIXME: module alias should be written when config is written only + #detect_devices::getModem(modules::any_conf->read); + (); +} + +my @thirdparty_settings = ( + { + matching => qr/^Hcf:/, + description => 'HCF 56k Modem', + url => 'http://www.linuxant.com/drivers/hcf/', + name => 'hcfpcimodem', + kernel_module => { + test_file => 'hcfpciengine', + }, + tools => { + test_file => '/usr/sbin/hcfpciconfig', + }, + device => '/dev/ttySHCF0', + post => '/usr/sbin/hcfpciconfig --auto', + restart_service => 'hcfpci', + }, + + { + matching => qr/^Hsf:/, + description => 'HSF 56k Modem', + url => 'http://www.linuxant.com/drivers/hsf/', + name => 'hsfmodem', + kernel_module => { + test_file => 'hsfengine', + }, + tools => { + test_file => '/usr/sbin/hsfconfig', + }, + device => '/dev/ttySHSF0', + post => '/usr/sbin/hsfconfig --auto', + restart_service => 'hsf', + }, + + { + matching => qr/^LT:/, + description => 'LT WinModem', + url => 'http://www.heby.de/ltmodem/', + name => 'ltmodem', + kernel_module => 1, + tools => { + test_file => '/etc/devfs/conf.d/ltmodem.conf', + }, + device => '/dev/ttyS14', + links => [ + 'http://linmodems.technion.ac.il/Ltmodem.html', + 'http://linmodems.technion.ac.il/packages/ltmodem/', + ], + }, + + { + matching => [ list_modules::category2modules('network/slmodem') ], + description => 'Smartlink WinModem', + url => 'http://www.smlink.com/content.aspx?id=135/', + name => 'slmodem', + kernel_module => 1, + tools => { + test_file => '/usr/sbin/slmodemd', + }, + device => '/dev/ttySL0', + post => sub { + my ($driver) = @_; + addVarsInSh("$::prefix/etc/sysconfig/slmodemd", { SLMODEMD_MODULE => $driver }); + }, + restart_service => "slmodemd", + }, + + { + name => 'sm56', + description => 'Motorola SM56 WinModem', + url => 'http://www.motorola.com/softmodem/driver.htm#linux', + kernel_module => { + package => 'sm56', + }, + no_club => 1, + device => '/dev/sm56', + }, +); + +sub get_thirdparty_settings { \@thirdparty_settings } + +sub get_providers { + my $db_path = "/usr/share/apps/kppp/Provider"; + #$in->do_pkgs->ensure_is_installed('kdenetwork-kppp-provider', $db_path); + my $separator = "|"; + my %providers; + foreach (all($::prefix . $db_path)) { + s!_! !g; + my $country = $_; + my $t_country = translate($country); + my $country_root = $::prefix . $db_path . '/' . $country; + foreach (grep { $_ ne '.directory' } all($country_root)) { + my $path = $country_root . $_; + s/%([0-9]{3})/chr(int($1))/eg; + $providers{$t_country . $separator . $_} = { path => $path }; + } + } + (\%providers, $separator); +} + +1; diff --git a/lib/network/connection/ppp.pm b/lib/network/connection/ppp.pm new file mode 100644 index 0000000..d1db2b3 --- /dev/null +++ b/lib/network/connection/ppp.pm @@ -0,0 +1,138 @@ +package network::connection::ppp; + +use strict; +use common; + +use base qw(network::connection); + +my %authentication_methods = ( + script => N_("Script-based"), + pap => N_("PAP"), + terminal_ => N_("Terminal-based"), + chap => N_("CHAP"), + pap_chap => N_("PAP/CHAP"), +); + +my @kppp_authentication_methods = qw(script pap terminal chap pap_chap); +my @secrets_files = qw(pap-secrets chap-secrets); + +sub get_access_settings { + my ($self) = @_; + [ + { label => N("Account Login (user name)"), val => \$self->{access}{login} }, + { label => N("Account Password"), val => \$self->{access}{password}, hidden => 1 }, + ]; +} + +sub get_secret { + my ($_self, $login) = @_; + foreach (@secrets_files) { + my $file = "$::prefix/etc/ppp/$_"; + foreach (cat_($file)) { + my ($l, undef, $password) = split(' '); + if ($l && $password) { + s/^(['"]?)(.*)\1$/$2/ foreach $l, $password; + return $password if $l eq $login; + } + } + } +} + +sub write_secrets { + my ($self) = @_; + foreach (@secrets_files) { + my $file = "$::prefix/etc/ppp/$_"; + substInFile { + s/^'$self->{access}{login}'.*\n//; + $_ .= "\n'$self->{access}{login}' * '$self->{access}{password}' * \n" if eof; + } $file; + chmod 0600, $file; + } +} + +sub get_options { + #- options: PAPNAME PEERDNS +} + +sub get_tty_device { "/dev/modem" } + +sub build_ifcfg_settings { + my ($self) = @_; + my $modemport = $self->get_tty_device; + my $settings = put_in_hash($self->{settings}, { + if_($modemport, MODEMPORT => $modemport), + LINESPEED => "115200", + PERSIST => "yes", + DEBUG => "yes", + DEFROUTE => "yes", + }); + $self->SUPER::build_ifcfg_settings($settings); +} + +sub build_chat { + my ($self) = @_; + #- required access parameters: + #- dial_number + #- optional: + #- auth_method: key of %authentication_methods + #- login + #- password + #- at_commands: array ref of AT commands + (map { "ABORT $_" } "BUSY", "ERROR", "'NO CARRIER'", "'NO DIALTONE'", "'Invalid Login'", "'Login incorrect'", "VOICE", "'NO ANSWER'", "DELAYED", "'SIM PIN'"), + qq('' ATZ), + if_(ref $self->{access}{at_commands}, map { qq(OK-AT-OK '$_') } @{$self->{access}{at_commands}}), + qq(OK 'ATDT$self->{access}{dial_number}'), + qq(TIMEOUT 120), + qq(CONNECT ''), + if_(member($self->{access}{auth_method}, qw(script terminal)), + qq('ogin:--ogin:' '$self->{access}{login}'), + qq('ord:' '$self->{access}{password}')), + qq(TIMEOUT 5), + qq('~--' ''); +} + +sub write_chat { + my ($self) = @_; + my $interface = $self->get_interface; + my $chat_file = "/etc/sysconfig/network-scripts/chat-$interface"; + output_with_perm($::prefix . $chat_file, 0755, join("\n", $self->build_chat, '')); +} + +sub get_peer_default_options { + my ($_self) = @_; + qw(noauth defaultroute usepeerdns); +} + +sub build_peer { + my ($self) = @_; + #- options: + #- init + #- connect + #- pty + #- plugin + if ($self->{access}{dial_number}) { + my $interface = $self->get_interface; + my $chat_file = "/etc/sysconfig/network-scripts/chat-$interface"; + $self->{access}{peer}{connect} ||= qq("/usr/sbin/chat -v -f $chat_file"); + } + $self->get_peer_default_options, + (map { if_($self->{access}{peer}{$_}, $_ . " " . $self->{access}{peer}{$_}) } qw(init connect pty plugin)), + if_($self->{access}{login}, qq(user "$self->{access}{login}")); +} + +sub write_peer { + my ($self) = @_; + my $interface = $self->get_interface; + my $peer_file = "/etc/ppp/peers/$interface"; + output_with_perm($::prefix . $peer_file, 0755, join("\n", $self->build_peer, '')); +} + +sub write_settings { + my ($self) = @_; + $self->write_secrets if $self->{access}{login}; + $self->write_chat if $self->{access}{dial_number}; + $self->write_peer; + $self->network::connection::write_settings; +} + +1; diff --git a/lib/network/connection/providers/cellular.pm b/lib/network/connection/providers/cellular.pm new file mode 100644 index 0000000..ef630b4 --- /dev/null +++ b/lib/network/connection/providers/cellular.pm @@ -0,0 +1,28 @@ +package network::connection::providers::cellular; + +use common; +use utf8; + +# http://www.reqwireless.com/apns.html +# http://wiki.mig33.com/mig33/show/apn +# http://www.unlocks.co.uk/gprs_settings.php +# http://www.opera.com/products/smartphone/docs/connect/ +# http://www.taniwha.org.uk/gprs.html + +our %data = ( + N("France") . "|Orange Grand Public" => { + apn => "orange.fr", + login => "orange", + password => "orange", + }, + N("France") . "|Orange Entreprises" => { + apn => "internet-entreprise", + login => "orange", + password => "orange", + }, + N("France") . "|SFR" => { + apn => "websfr", + }, +); + +1; diff --git a/lib/network/adsl_consts.pm b/lib/network/connection/providers/xdsl.pm index c3cc03b..6956e1c 100644 --- a/lib/network/adsl_consts.pm +++ b/lib/network/connection/providers/xdsl.pm @@ -1,20 +1,23 @@ -package network::adsl_consts; # $Id$ +# -*- coding: utf-8 -*- +package network::connection::providers::xdsl; # $Id: xdsl.pm 59309 2006-09-01 12:08:15Z tv $ # This should probably be splitted out into ldetect-lst as some provider db -use vars qw(@ISA @EXPORT); use common; use utf8; -@ISA = qw(Exporter); -@EXPORT = qw(@adsl_data); - # Originally from : # http://www.eagle-usb.org/article.php3?id_article=23 # http://www.sagem.com/web-modems/download/support-fast1000-fr.htm # http://perso.wanadoo.fr/michel-m/protocolesfai.htm +# Then other ISP found in : +# http://www.adslayuda.com/Comtrend500+file-16.html + +# the output is provided in html at http://faq.eagle-usb.org/wakka.php?wiki=ListConfigADSL +# this file should be put in /usr/share/eagle-usb/ for eagle-usb driver +# or in /usr/lib/libDrakX/network/ as part of the drakxtools -our %adsl_data = ( +our %data = ( ## format chosen is the following : # country|provider => { VPI, VCI_hexa, ... } all parameters # country is automagically translated into LANG with N function @@ -32,11 +35,11 @@ our %adsl_data = ( # 6 RFC2364 PPPoA VCmux # see http://faq.eagle-usb.org/wakka.php?wiki=AdslDescription # dns are provided for when !usepeerdns in peers config file - # dnsServer2 dnsServer3 : main DNS - # dnsServers_text : string with any valid DNS (when more than 2) + # dnsServers : array ref with any valid DNS (order matters) # DOMAINNAME2 : used for search key in /etc/resolv.conf # method : PPPoA, pppoe, static or dhcp - # methods_all : all methods for connection with this ISP (when more than 1) + # login_format : e.g. fti/login for France Telecom + # encryption : for pppd connection, when encryption is supported # modem : model of modem provided by ISP or tested with ISP # please forward updates to http://forum.eagle-usb.org # try to order alphabetically by country (in English) / ISP (local language) @@ -48,19 +51,37 @@ our %adsl_data = ( vci => 23, Encapsulation => 1, method => 'pppoe', - dnsServer2 => '82.101.136.29', - dnsServer3 => '82.101.136.206', + dnsServers => [ qw(82.101.136.29 82.101.136.206) ], + }, + + N("Algeria") . "|Algerie Telecom (FAWRI)" => + { + provider_id => 'DZ02', + vpi => 0, + vci => 26, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(61.88.88.88 205.252.144.228) ], }, N("Argentina") . "|Speedy" => { provider_id => 'AR01', - vpi => 1, + vpi => 8, vci => 23, Encapsulation => 1, method => 'pppoe', - dnsServer2 => '200.51.254.238', - dnsServer3 => '200.51.209.22', + dnsServers => [ qw(200.51.254.238 200.51.209.22) ], + }, + + N("Argentina") . "|Arnet" => + { + provider_id => 'AR02', + vpi => 8, + vci => 21, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(200.45.191.35 200.45.191.40) ], }, N("Austria") . "|Any" => @@ -90,6 +111,36 @@ our %adsl_data = ( method => 'pppoe', }, + N("Australia") . "|Arachnet" => + { + provider_id => 'AU01', + url_tech => "http://www.ains.com.au/consumer/support/technical.htm", + vpi => 8, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Australia") . "|Speedstream On net" => + { + provider_id => 'AU02', + url_tech => "http://www.ains.com.au/consumer/support/technical.htm", + vpi => 8, + vci => 22, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Australia") . "|Speedstream Off net" => + { + provider_id => 'AU03', + url_tech => "http://www.ains.com.au/consumer/support/technical.htm", + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + N("Belgium") . "|ADSL Office" => { provider_id => 'BE04', @@ -106,8 +157,7 @@ our %adsl_data = ( vci => 23, Encapsulation => 6, method => 'pppoa', - dnsServer2 => '212.35.2.1', - dnsServer3 => '212.35.2.2', + dnsServers => [ qw(212.35.2.1 212.35.2.2 212.233.1.34 212.233.2.34) ], DOMAINNAME2 => 'tiscali.be', }, @@ -129,6 +179,15 @@ our %adsl_data = ( method => 'pppoa', }, + N("Belgium") . "|Scarlet ADSL" => + { + provider_id => 'BE05', + vpi => 8, + vci => 20, + Encapsulation => 6, + method => 'pppoa', + }, + N("Brazil") . "|Speedy/Telefonica" => { provider_id => 'BR01', @@ -136,8 +195,7 @@ our %adsl_data = ( vci => 23, Encapsulation => 1, method => 'pppoe', - dnsServer2 => '200.204.0.10', - dnsServer3 => '200.204.0.138', + dnsServers => [ qw(200.204.0.10 200.204.0.138) ], }, N("Brazil") . "|Velox/Telemar" => @@ -365,23 +423,61 @@ our %adsl_data = ( method => 'pppoe', }, - N("Czech Republic") . "|Cesky Telecom" => + N("Czech Republic") . "|Cesky Telecom PPPoA" => { provider_id => 'CZ01', url_tech => 'http://www.telecom.cz/domacnosti/internet/pristupove_sluzby/broadband/vse_o_kz_a_moznostech_instalace.php', vpi => 8, - vci => 48, + vci => 30, Encapsulation => 6, method => 'pppoa', }, + N("Czech Republic") . "|Cesky Telecom PPPoE" => + { + provider_id => 'CZ02', + url_tech => 'http://www.telecom.cz/zakaznicka_podpora/dokumenty_ke_stazeni/internet_expres.php', + vpi => 8, + vci => 30, + Encapsulation => 1, + method => 'pppoe', + }, + N("Denmark") . "|Any" => { provider_id => 'DK01', vpi => 0, vci => 65, - method => 'pppoe', Encapsulation => 3, + method => 'pppoe', + }, + + N("Denmark") . "|Cybercity" => + { + provider_id => 'DK02', + vpi => 0, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Denmark") . "|Tiscali" => + { + provider_id => 'DK03', + vpi => 0, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Egypt") . "|Raya Telecom" => + { + provider_id => 'EG01', + vpi => 8, + vci => 50, + method => 'pppoa', + Encapsulation => 6, + dnsServers => [ qw(62.240.110.197 62.240.110.198) ], }, N("Finland") . "|Sonera" => @@ -399,8 +495,20 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '213.228.0.23', - dnsServer3 => '212.27.32.176', + CMVep => 'FR', + dnsServers => [ qw(213.228.0.23 212.27.32.176) ], + method => 'pppoa', + DOMAINNAME2 => 'free.fr', + }, + + N("France") . "|Free non dégroupé ADSL Max" => + { + provider_id => 'FR11', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR04', + dnsServers => [ qw(213.228.0.23 212.27.32.176) ], method => 'pppoa', DOMAINNAME2 => 'free.fr', }, @@ -411,8 +519,8 @@ our %adsl_data = ( vpi => 8, vci => 24, Encapsulation => 4, - dnsServer2 => '213.228.0.23', - dnsServer3 => '212.27.32.176', + CMVep => 'FR04', + dnsServers => [ qw(213.228.0.23 212.27.32.176 213.228.0.68 212.27.32.176 212.27.32.177 212.27.39.2 212.27.39.1) ], method => 'dhcp', DOMAINNAME2 => 'free.fr', }, @@ -423,8 +531,8 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '212.30.93.108', - dnsServer3 => '212.203.124.146', + CMVep => 'FR', + dnsServers => [ qw(212.30.93.108 212.203.124.146 62.62.156.12 62.62.156.13) ], method => 'pppoa', }, @@ -434,9 +542,22 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '212.94.174.85', - dnsServer3 => '212.94.174.86', + CMVep => 'FR', + dnsServers => [ qw(212.94.174.85 212.94.174.86) ], + method => 'pppoa', + login_format => 'login@cegetel.net', + }, + + N("France") . "|Cegetel ADSL Max 8 Mb" => + { + provider_id => 'FR10', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR10', + dnsServers => [ qw(212.94.174.85 212.94.174.86) ], method => 'pppoa', + login_format => 'login@cegetel.net', }, N("France") . "|Club-Internet" => @@ -445,8 +566,8 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '194.117.200.10', - dnsServer3 => '194.117.200.15', + CMVep => 'FR', + dnsServers => [ qw(194.117.200.10 194.117.200.15) ], method => 'pppoa', DOMAINNAME2 => 'club-internet.fr', }, @@ -457,9 +578,10 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '80.10.246.2', - dnsServer3 => '80.10.246.129', + CMVep => 'FR', + dnsServers => [ qw(80.10.246.2 80.10.246.129) ], method => 'pppoa', + login_format => 'fti/login', DOMAINNAME2 => 'wanadoo.fr', }, @@ -469,8 +591,8 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '212.151.136.242', - dnsServer3 => '130.244.127.162', + CMVep => 'FR', + dnsServers => [ qw(212.151.136.242 130.244.127.162 212.151.136.246) ], method => 'pppoa', }, @@ -480,8 +602,8 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 5, - dnsServer2 => '213.36.80.1', - dnsServer3 => '213.36.80.2', + CMVep => 'FR', + dnsServers => [ qw(213.36.80.1 213.36.80.2) ], method => 'pppoa', }, @@ -491,8 +613,8 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '213.36.80.1', - dnsServer3 => '213.36.80.2', + CMVep => 'FR', + dnsServers => [ qw(213.36.80.1 213.36.80.2) ], method => 'pppoa', }, @@ -511,8 +633,17 @@ our %adsl_data = ( vpi => 1, vci => 20, Encapsulation => 1, - dnsServer2 => '195.20.224.234', - dnsServer3 => '194.25.2.129', + dnsServers => [ qw(195.20.224.234 194.25.2.129) ], + method => 'pppoe', + }, + + N("Germany") . "|Alice DSL" => + { + provider_id => 'DE03', + vpi => 1, + vci => 20, + Encapsulation => 1, + dnsServers => [ qw(213.191.73.65 213.191.74.20) ], method => 'pppoe', }, @@ -549,20 +680,34 @@ our %adsl_data = ( vpi => 8, vci => 30, Encapsulation => 6, - dnsServer2 => '192.115.106.10', - dnsServer3 => '192.115.106.11', + dnsServers => [ qw(192.115.106.10 192.115.106.11 192.115.106.35) ], method => 'pppoa', }, - N("Italy") . "|Libero.it" => + N("India") . "|Any" => { - provider_id => 'IT04', - url_tech => 'http://internet.libero.it/assistenza/adsl/installazione_ass.phtml', - vpi => 8, + provider_id => 'IN01', + vpi => 0, + vci => 20, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Iceland") . "|Islandssimi" => + { + provider_id => 'IS01', + vpi => 0, vci => 23, Encapsulation => 6, - dnsServer2 => '193.70.192.25', - dnsServer3 => '193.70.152.25', + method => 'pppoa', + }, + + N("Iceland") . "|Landssimi" => + { + provider_id => 'IS02', + vpi => 8, + vci => 30, + Encapsulation => 6, method => 'pppoa', }, @@ -572,8 +717,8 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '195.20.224.234', - dnsServer3 => '194.25.2.129', + CMVep => 'IT', + dnsServers => [ qw(195.20.224.234 194.25.2.129) ], method => 'pppoa', }, @@ -583,6 +728,7 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 3, + CMVep => 'IT', method => 'static', }, @@ -592,9 +738,33 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '195.20.224.234', - dnsServer3 => '194.25.2.129', + CMVep => 'IT', + dnsServers => [ qw(195.20.224.234 194.25.2.129) ], + method => 'pppoa', + }, + + N("Italy") . "|Libero.it" => + { + provider_id => 'IT04', + url_tech => 'http://internet.libero.it/assistenza/adsl/installazione_ass.phtml', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'IT', + dnsServers => [ qw(193.70.192.25 193.70.152.25) ], + method => 'pppoa', + }, + + N("Sri Lanka") . "|Srilanka Telecom" => + { + provider_id => 'LK01', + url_tech => 'http://www.sltnet.lk', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(203.115.0.1 203.115.0.18) ], method => 'pppoa', + encryption => 1, }, N("Lithuania") . "|Lietuvos Telekomas" => @@ -606,14 +776,34 @@ our %adsl_data = ( method => 'pppoe', }, + N("Mauritius") . "|wanadoo.mu" => + { + provider_id => 'MU01', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(202.123.2.6 202.123.2.11) ], + method => 'pppoa', + }, + + N("Mauritius") . "|Telecom Plus (Mauritius Telecom)" => + { + provider_id => 'MU02', + url_tech => 'http://www.telecomplus.net', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(202.123.1.6 202.123.1.11) ], + method => 'pppoa', + }, + N("Morocco") . "|Maroc Telecom" => { provider_id => 'MA01', vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '212.217.0.1', - dnsServer3 => '212.217.0.12', + dnsServers => [ qw(212.217.0.1 212.217.0.12) ], method => 'pppoa', }, @@ -632,7 +822,7 @@ our %adsl_data = ( vpi => 0, vci => 21, Encapsulation => 3, - method => 'dhcp', + method => 'pppoe', }, N("Netherlands") . "|Tiscali" => @@ -640,8 +830,8 @@ our %adsl_data = ( provider_id => 'NL03', vpi => 0, vci => 22, - Encapsulation => 3, - method => 'dhcp', + Encapsulation => 1, + method => 'pppoe', }, N("Netherlands") . "|Versatel" => @@ -650,54 +840,71 @@ our %adsl_data = ( vpi => 0, vci => 20, Encapsulation => 3, - method => 'dhcp', + method => 'pppoe', }, N("Norway") . "|Bluecom" => { + provider_id => 'NO01', method => 'dhcp', }, N("Norway") . "|Firstmile" => { + provider_id => 'NO02', method => 'dhcp', }, N("Norway") . "|NextGenTel" => { + provider_id => 'NO03', method => 'dhcp', }, N("Norway") . "|SSC" => { + provider_id => 'NO04', method => 'dhcp', }, N("Norway") . "|Tele2" => { + provider_id => 'NO05', method => 'dhcp', }, N("Norway") . "|Telenor ADSL" => { + provider_id => 'NO06', method => 'PPPoE', }, N("Norway") . "|Tiscali" => { + provider_id => 'NO07', vpi => 8, vci => 35, method => 'dhcp', }, + N("Pakistan") . "|Micronet BroadBand" => + { + provider_id => 'PK01', + vpi => 1, + vci => 20, + Encapsulation => 3, + dnsServers => [ qw(203.82.48.3 203.82.48.4) ], + method => 'pppoe', + encryption => 1, + }, + N("Poland") . "|Telekomunikacja Polska (TPSA/neostrada)" => { provider_id => 'PL01', vpi => 0, vci => 23, Encapsulation => 6, - dnsServer2 => '194.204.152.34', - dnsServer3 => '217.98.63.164', + dnsServers => [ qw(194.204.152.34 217.98.63.164) ], method => 'pppoa', }, @@ -708,8 +915,7 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 1, - dnsServer2 => '195.114.181.130', - dnsServer3 => '195.114.161.61', + dnsServers => [ qw(195.114.181.130 195.114.161.61) ], method => 'pppoe', }, @@ -727,13 +933,21 @@ our %adsl_data = ( provider_id => 'RU01', url_tech => 'http://stream.ru/s-requirements', vpi => 1, - vci => 50, + vci => 32, Encapsulation => 1, - dnsServer2 => '212.188.4.10', - dnsServer3 => '195.34.32.116', + dnsServers => [ qw(212.188.4.10 195.34.32.116) ], method => 'pppoe', }, - + + N("Singapore") . "|Singnet" => + { + provider_id => 'SG01', + vpi => 0, + vci => 64, + method => 'pppoa', + Encapsulation => 6, + }, + N("Senegal") . "|Sonatel Multimedia Sentoo" => { provider_id => 'SN01', @@ -751,8 +965,7 @@ our %adsl_data = ( vci => 20, method => 'pppoe', Encapsulation => 1, - dnsServer2 => '193.189.160.11', - dnsServer3 => '193.189.160.12', + dnsServers => [ qw(193.189.160.11 193.189.160.12) ], DOMAINNAME2 => 'siol.net', }, @@ -762,9 +975,10 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 1, - dnsServer2 => '80.58.32.33', - dnsServer3 => '80.58.0.97', + CMVep => 'ES', + dnsServers => [ qw(80.58.32.33 80.58.0.97) ], method => 'pppoe', + login_format => 'adslppp@telefonicanetpa / adslppp', }, N("Spain") . "|Telefónica ip fija" => @@ -773,9 +987,10 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 3, + CMVep => 'ES', + dnsServers => [ qw(80.58.32.33 80.58.0.97) ], method => 'static', - dnsServer2 => '80.58.32.33', - dnsServer3 => '80.58.0.97', + login_format => 'adslppp@telefonicanetpa / adslppp', }, N("Spain") . "|Wanadoo/Eresmas Retevision" => @@ -784,9 +999,11 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 6, - dnsServer2 => '80.58.0.33', - dnsServer3 => '80.58.32.97', + CMVep => 'ES', + dnsServers => [ qw(80.58.0.33 80.58.32.97) ], method => 'pppoa', + login_format => 'rtxxxxx@wanadooadsl', + encryption => 1, }, N("Spain") . "|Wanadoo PPPoE" => @@ -795,6 +1012,7 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 1, + CMVep => 'ES', method => 'pppoe', }, @@ -804,6 +1022,7 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 3, + CMVep => 'ES', method => 'static', }, @@ -813,7 +1032,9 @@ our %adsl_data = ( vpi => 1, vci => 20, Encapsulation => 6, + CMVep => 'ES', method => 'pppoa', + login_format => 'login@tiscali.es', }, N("Spain") . "|Arrakis" => @@ -822,6 +1043,7 @@ our %adsl_data = ( vpi => 0, vci => 23, Encapsulation => 6, + CMVep => 'ES', method => 'pppoa', }, @@ -831,6 +1053,7 @@ our %adsl_data = ( vpi => 0, vci => 23, Encapsulation => 6, + CMVep => 'ES', method => 'pppoa', }, @@ -840,6 +1063,7 @@ our %adsl_data = ( vpi => 0, vci => 21, Encapsulation => 6, + CMVep => 'ES', method => 'pppoa', }, @@ -849,6 +1073,7 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 1, + CMVep => 'ES', method => 'pppoe', }, @@ -858,6 +1083,7 @@ our %adsl_data = ( vpi => 1, vci => 21, Encapsulation => 6, + CMVep => 'ES', method => 'pppoa', }, @@ -867,7 +1093,9 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 1, + CMVep => 'ES', method => 'pppoe', + login_format => 'adXXXXXXXXX@yacomadsl', }, N("Spain") . "|Ya.com static" => @@ -876,7 +1104,46 @@ our %adsl_data = ( vpi => 8, vci => 20, Encapsulation => 3, + CMVep => 'ES', method => 'static', + login_format => 'adXXXXXXXXX@yacomadsl', + }, + + N("Spain") . "|Arsys" => + { + provider_id => 'ES14', + vpi => 1, + vci => 21, + Encapsulation => 1, + CMVep => 'ES', + dnsServers => [ qw(217.76.128.4 217.76.129.4) ], + method => 'pppoe', + login_format => 'login@arsystel', + }, + + N("Spain") . "|Terra" => + { + provider_id => 'ES15', + vpi => 8, + vci => 20, + Encapsulation => 1, + CMVep => 'ES', + dnsServers => [ qw(213.4.132.1 213.4.141.1) ], + method => 'pppoe', + login_format => 'login@terraadsl', + }, + + N("Spain") . "|Jazztel" => + { + provider_id => 'ES16', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'ES', + dnsServers => [ qw(62.14.63.145 62.14.2.1) ], + method => 'pppoa', + login_format => 'username@adsl', + encryption => 1, }, N("Sweden") . "|Telia" => @@ -903,12 +1170,11 @@ our %adsl_data = ( vpi => 8, vci => 23, Encapsulation => 5, - dnsServer2 => '195.186.4.108', - dnsServer3 => '195.186.4.109', + dnsServers => [ qw(195.186.4.108 195.186.4.109) ], method => 'pppoa', }, - N("Switzerland") . "|Tiscali.ch" => + N("Switzerland") . "|VTX Datacomm (ex-Tiscali)" => { provider_id => 'CH03', vpi => 8, @@ -923,21 +1189,32 @@ our %adsl_data = ( vpi => 0, vci => 64, Encapsulation => 1, - dnsServer2 => '203.144.225.242', - dnsServer3 => '203.144.225.72', + dnsServers => [ qw(203.144.225.242 203.144.225.72 203.144.223.66) ], method => 'pppoe', }, N("Tunisia") . "|Planet.tn" => { - provider_id => 'TH01', + provider_id => 'TU01', url_tech => 'http://www.planet.tn/', vpi => 0, vci => 23, Encapsulation => 5, - dnsServer2 => '193.95.93.77', - dnsServer3 => '193.95.66.10', + dnsServers => [ qw(193.95.93.77 193.95.66.10) ], + method => 'pppoe', + }, + + N("Turkey") . "|TTnet" => + { + provider_id => 'TR01', + url_tech => 'http://www.ttnet.net.tr', + vpi => 8, + vci => 23, + Encapsulation => 1, + dnsServers => [ qw(195.175.37.14 195.175.37.69) ], method => 'pppoe', + encryption => 1, + login_format => 'login@ttnet', }, N("United Arab Emirates") . "|Etisalat" => @@ -946,8 +1223,7 @@ our %adsl_data = ( vpi => 0, vci => 32, Encapsulation => 5, - dnsServer2 => '213.42.20.20', - dnsServer3 => '195.229.241.222', + dnsServers => [ qw(213.42.20.20 195.229.241.222) ], method => 'pppoa', }, @@ -957,8 +1233,7 @@ our %adsl_data = ( vpi => 0, vci => 26, Encapsulation => 6, - dnsServer2 => '212.74.112.66', - dnsServer3 => '212.74.112.67', + dnsServers => [ qw(212.74.112.66 212.74.112.67) ], method => 'pppoa', }, @@ -968,12 +1243,10 @@ our %adsl_data = ( vpi => 0, vci => 26, Encapsulation => 6, - dnsServer2 => '194.74.65.69', - dnsServer3 => '194.72.9.38', + dnsServers => [ qw(194.74.65.69 194.72.9.38) ], method => 'pppoa', }, ); - 1; diff --git a/lib/network/connection/wireless.pm b/lib/network/connection/wireless.pm new file mode 100644 index 0000000..df1a210 --- /dev/null +++ b/lib/network/connection/wireless.pm @@ -0,0 +1,744 @@ +package network::connection::wireless; + +use strict; +use common; + +use base qw(network::connection::ethernet); + +use strict; +use common; + +sub get_type_name() { N("Wireless") } +sub get_type_icon() { 'wireless-24.png' } +sub get_devices { + my ($_class, %options) = @_; + require detect_devices; + my @devices = detect_devices::probe_category('network/wireless'); + my @wireless = grep { detect_devices::is_wireless_interface($_) } detect_devices::get_lan_interfaces(); + my @all_devices = (@devices, network::connection::ethernet::get_unlisted_devices(\@wireless, \@devices)); + foreach (@all_devices) { + my $interface = network::connection::ethernet::device_to_interface($_) or next; + my $driver = network::connection::ethernet::interface_to_driver($interface) or next; + $_->{driver} = $driver if $driver; + } + @all_devices, + if_(!$options{automatic_only}, { + driver => 'ndiswrapper', + description => N("Use a Windows driver (with ndiswrapper)"), + }); +} + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + require detect_devices; + detect_devices::is_wireless_interface($ifcfg->{DEVICE}) || exists $ifcfg->{WIRELESS_MODE}; +} + +sub get_metric { 35 } + +#- class attributes: +#- network: ID of the selected network + +our %wireless_enc_modes = ( + none => N_("None"), + open => N_("Open WEP"), + restricted => N_("Restricted WEP"), + 'wpa-psk' => N_("WPA Pre-Shared Key"), +); + +my @thirdparty_settings = ( + { + name => 'zd1201', + description => 'ZyDAS ZD1201', + url => 'http://linux-lc100020.sourceforge.net/', + firmware => { + test_file => 'zd1201*.fw', + }, + }, + + (map { + { + name => "ipw${_}", + description => "Intel(R) PRO/Wireless ${_}", + url => "http://ipw${_}.sourceforge.net/", + firmware => { + url => "http://ipw${_}.sourceforge.net/firmware.php", + test_file => "ipw$_-*.fw", + }, + }; + } (2100, 2200)), + + { + name => "ipw3945", + description => "Intel(R) PRO/Wireless 3945", + url => "http://ipw3945.sourceforge.net/", + firmware => { + package => "ipw3945-ucode", + test_file => "ipw3945.ucode", + }, + tools => { + package => "ipw3945d", + test_file => '/usr/sbin/ipw3945d', + }, + }, + + { + name => 'prism54', + description => 'Prism GT / Prism Duette / Prism Indigo Chipsets', + url => 'http://prism54.org/', + firmware => { + url => 'http://prism54.org/~mcgrof/firmware/', + test_file => "isl38*", + }, + }, + + { + name => 'atmel', + matching => [ qw(at76_usb atmel_cs atmel_pci) ], + description => 'Atmel at76c50x cards', + url => 'http://thekelleys.org.uk/atmel/', + firmware => { + test_file => 'atmel_at76c50*', + }, + links => 'http://at76c503a.berlios.de/', + }, + + { + name => 'madwifi', + matching => 'ath_pci', + description => 'Multiband Atheros Driver for WiFi', + url => 'http://madwifi.org/', + kernel_module => 1, + tools => { + optional => 1, + test_file => '/usr/bin/athstats', + }, + }, + + { + name => 'prism2', + matching => qr/^prism2_/, + description => 'Prism2 based cards', + tools => { + package => 'prism2-utils', + test_file => '/sbin/wlanctl-ng', + }, + }, + + { + name => 'zd1211', + matching => 'zd1211rw', + description => 'ZD1211 chip', + firmware => { + url => 'http://sourceforge.net/projects/zd1211/', + test_file => 'zd1211/zd1211_*', + }, + }, + + { + name => 'bcm43xx', + description => 'Broadcom bcm43xx wireless chips', + url => 'http://bcm43xx.berlios.de/', + firmware => { + test_file => 'bcm43xx_microcode*.fw', + extract => { + name => 'bcm43xx-fwcutter', + test_file => '/usr/bin/bcm43xx-fwcutter', + windows_source => 'bcmwl5.sys', + default_source => 'bcmwl5.sys', + run => sub { + my ($file) = @_; + run_program::rooted($::prefix, '/usr/bin/bcm43xx-fwcutter', + '-w', $network::thirdparty::firmware_directory, $file); + }, + }, + }, + }, + + { + name => 'acx100', + matching => [ qw(acx-pci acx-usb) ], + description => 'ACX100/ACX111/TNETW1450', + firmware => { + url => 'http://acx100.sourceforge.net/wiki/Firmware', + test_file => 'tiacx1*', + no_package => 1, + }, + }, + + { + name => 'ndiswrapper', + description => 'Wireless device using ndiswrapper (windows drivers)', + tools => { + test_file => '/usr/sbin/ndiswrapper', + }, + firmware => { + user_install => sub { + my ($settings, $in) = @_; + require network::ndiswrapper; + $settings->{device} = network::ndiswrapper::select_device($in) or return; + $settings->{device}{driver} = $settings->{name}; + network::ndiswrapper::setup_device($in, $settings->{device}); + }, + url => 'http://ndiswrapper.sourceforge.net/mediawiki/index.php/List', + explanations => N_("Firmware files are required for this device."), + no_package => 1, + }, + }, + + { + name => 'rt61', + description => 'Ralink RT61 802.11abg WLAN', + firmware => { + url => 'http://rt2x00.serialmonkey.com/', + test_file => 'rt2661.bin', + }, + }, + + { + name => 'rt73', + description => 'Ralink RT73 802.11abg WLAN', + firmware => { + url => 'http://rt2x00.serialmonkey.com/', + test_file => 'rt73.bin', + }, + }, + +); + +sub get_packages { 'wireless-tools' } + +sub get_thirdparty_settings() { + \@thirdparty_settings; +} + +sub setup_thirdparty { + my ($self, $in) = @_; + require network::rfswitch; + network::rfswitch::configure(); + if ($self->get_driver eq 'ndiswrapper') { + require network::ndiswrapper; + my @devices = map { network::ndiswrapper::present_devices($_) } network::ndiswrapper::installed_drivers(); + return {} if member($self->{device}, @devices) && network::ndiswrapper::find_interface($self->{device}); + } + my $thirdparty = $self->SUPER::setup_thirdparty($in); + my $driver = $self->get_driver; + if ($self->{thirdparty} && $driver eq 'ipw3945' && !$self->rf_killed && !$self->SUPER::check_device) { + log::explanations("Reloading module $driver"); + eval { modules::unload($driver) }; + eval { modules::load($driver) }; + } + $thirdparty; +} + +sub rf_killed { + my ($self) = @_; + if ($self->{device}{sysfs_device}) { + my $rf_kill_path = $self->{device}{sysfs_device} . "/rf_kill"; + if (-e $rf_kill_path) { + my $rf_kill = chomp_(cat_($rf_kill_path)); + #- for ipw drivers, 0 means no RF kill switch + return $rf_kill != 0; + } + } + undef; +} + +sub check_device { + my ($self) = @_; + if ($self->rf_killed) { + $self->{device}{error} = N("Your wireless card is disabled, please enable the wireless switch (RF kill switch) first."); + return 0; + } + return $self->SUPER::check_device; +} + +sub load_interface_settings { + my ($self) = @_; + $self->SUPER::load_interface_settings; +} + +sub get_networks { + my ($self) = @_; + require network::monitor; + ($self->{networks}, $self->{control}{roaming}) = network::monitor::list_wireless(undef, $self->get_interface); + $self->{networks}; +} + +sub guess_network { + my ($_self) = @_; + #- FIXME: try to find the AP matching $self->{ifcfg}{WIRELESS_ESSID}; +} + +sub get_network_ifcfg { + my ($ssid) = @_; + require network::network; + my $file = $::prefix . $network::network::wireless_d . '/' . $ssid; + -f $file && { getVarsFromSh($file) }; +} + +sub guess_network_access_settings { + my ($self) = @_; + + my $ifcfg; + my $network = $self->get_selected_network; + $ifcfg = $network ? + get_network_ifcfg($network->{ap}) || get_network_ifcfg($network->{essid}) : + $self->{ifcfg}; + $ifcfg ||= {}; + + $self->{access}{network}{essid} = $network && $network->{essid} || $ifcfg->{WIRELESS_ESSID} || !$network && "any"; + ($self->{access}{network}{key}, my $restricted) = get_wep_key_from_iwconfig($ifcfg->{WIRELESS_ENC_KEY}); + $self->{access}{network}{encryption} = + $network && $network->{flags} =~ /wpa/i ? + 'wpa-psk' : + $network && $network->{flags} =~ /wep/i || $self->{access}{network}{key} ? + ($restricted ? 'restricted' : 'open') : + 'none'; + + undef $self->{ifcfg}{WIRELESS_IWPRIV} if is_old_rt2x00($self->get_driver) && $self->{ifcfg}{WIRELESS_IWPRIV} =~ /WPAPSK/; + + $self->{control}{roaming} = exists $self->{ifcfg}{WIRELESS_WPA_DRIVER} && !is_old_rt2x00($self->get_driver); + + $self->{access}{network}{mode} = + $network && $network->{mode} || + $ifcfg->{WIRELESS_MODE} || + 'Managed'; +} + +sub get_network_access_settings_label { N("Wireless settings") } + +sub get_network_access_settings { + my ($self) = @_; + [ + { label => N("Operating Mode"), val => \$self->{access}{network}{mode}, + list => [ N_("Ad-hoc"), N_("Managed"), N_("Master"), N_("Repeater"), N_("Secondary"), N_("Auto") ], + format => \&translate, + }, + { label => N("Network name (ESSID)"), val => \$self->{access}{network}{essid}, + disabled => sub { my $network = $self->get_selected_network; $network && $network->{essid} } }, + { label => N("Encryption mode"), val => \$self->{access}{network}{encryption}, list => [ keys %wireless_enc_modes ], + sort => 1, format => sub { translate($wireless_enc_modes{$_[0]}) } }, + { label => N("Encryption key"), val => \$self->{access}{network}{key}, + disabled => sub { $self->{access}{network}{encryption} eq 'none' } }, + { label => N("Network ID"), val => \$self->{ifcfg}{WIRELESS_NWID}, advanced => 1 }, + { label => N("Operating frequency"), val => \$self->{ifcfg}{WIRELESS_FREQ}, advanced => 1 }, + { label => N("Sensitivity threshold"), val => \$self->{ifcfg}{WIRELESS_SENS}, advanced => 1 }, + { label => N("Bitrate (in b/s)"), val => \$self->{ifcfg}{WIRELESS_RATE}, advanced => 1 }, + { label => N("RTS/CTS"), val => \$self->{ifcfg}{WIRELESS_RTS}, advanced => 1, + help => N("RTS/CTS adds a handshake before each packet transmission to make sure that the +channel is clear. This adds overhead, but increase performance in case of hidden +nodes or large number of active nodes. This parameter sets the size of the +smallest packet for which the node sends RTS, a value equal to the maximum +packet size disable the scheme. You may also set this parameter to auto, fixed +or off.") + }, + { label => N("Fragmentation"), val => \$self->{ifcfg}{WIRELESS_FRAG}, advanced => 1 }, + { label => N("iwconfig command extra arguments"), val => \$self->{ifcfg}{WIRELESS_IWCONFIG}, advanced => 1, + help => N("Here, one can configure some extra wireless parameters such as: +ap, channel, commit, enc, power, retry, sens, txpower (nick is already set as the hostname). + +See iwconfig(8) man page for further information."), + }, + { label => + #-PO: split the "xyz command extra argument" translated string into two lines if it's bigger than the english one + N("iwspy command extra arguments"), val => \$self->{ifcfg}{WIRELESS_IWSPY}, advanced => 1, + help => N("iwspy is used to set a list of addresses in a wireless network +interface and to read back quality of link information for each of those. + +This information is the same as the one available in /proc/net/wireless : +quality of the link, signal strength and noise level. + +See iwpspy(8) man page for further information."), + }, + { label => N("iwpriv command extra arguments"), val => \$self->{ifcfg}{WIRELESS_IWPRIV}, advanced => 1, + disabled => sub { $self->need_rt2x00_iwpriv }, + help => N("iwpriv enable to set up optionals (private) parameters of a wireless network +interface. + +iwpriv deals with parameters and setting specific to each driver (as opposed to +iwconfig which deals with generic ones). + +In theory, the documentation of each device driver should indicate how to use +those interface specific commands and their effect. + +See iwpriv(8) man page for further information."), + }, + ]; +} + +sub check_network_access_settings { + my ($self) = @_; + + if ($self->{access}{network}{encryption} ne 'none' && !$self->{access}{network}{key}) { + $self->{network_access}{error}{message} = N("An encryption key is required."); + $self->{network_access}{error}{field} = \$self->{access}{network}{key}; + return 0; + } + + if ($self->{ifcfg}{WIRELESS_FREQ} && $self->{ifcfg}{WIRELESS_FREQ} !~ /[0-9.]*[kGM]/) { + $self->{network_access}{error}{message} = N("Freq should have the suffix k, M or G (for example, \"2.46G\" for 2.46 GHz frequency), or add enough '0' (zeroes)."); + $self->{network_access}{error}{field} = \$self->{ifcfg}{WIRELESS_FREQ}; + return 0; + } + + if ($self->{ifcfg}{WIRELESS_RATE} && $self->{ifcfg}{WIRELESS_RATE} !~ /[0-9.]*[kGM]/) { + $self->{network_access}{error}{message} = N("Rate should have the suffix k, M or G (for example, \"11M\" for 11M), or add enough '0' (zeroes)."); + $self->{network_access}{error}{field} = \$self->{ifcfg}{WIRELESS_RATE}; + return 0; + } + + return 1; +} + +sub get_control_settings { + my ($self) = @_; + [ + @{$self->SUPER::get_control_settings}, + { text => N("Allow access point roaming"), val => \$self->{control}{roaming}, type => "bool", + disabled => sub { is_wpa_supplicant_blacklisted($self->get_driver) } }, + ]; +} + +sub need_wpa_supplicant { + my ($self) = @_; + ($self->{control}{roaming} || $self->{access}{network}{encryption} eq 'wpa-psk') && !is_old_rt2x00($self->get_driver); +} + +sub install_packages { + my ($self, $in) = @_; + if ($self->need_wpa_supplicant) { + $in->do_pkgs->ensure_is_installed('wpa_supplicant', '/usr/sbin/wpa_supplicant') or return; + } + $self->SUPER::install_packages($in); +} + + +sub build_ifcfg_settings { + my ($self) = @_; + my $settings = { + WIRELESS_MODE => $self->{access}{network}{mode}, + if_($self->need_wpa_supplicant, + WIRELESS_WPA_DRIVER => wpa_supplicant_get_driver($self->get_driver), + MII_NOT_SUPPORTED => 'no', + ), + WIRELESS_ESSID => $self->{access}{network}{essid}, + if_($self->{access}{network}{encryption} ne 'none', + WIRELESS_ENC_KEY => convert_wep_key_for_iwconfig($self->{access}{network}{key}, $self->{access}{network}{encryption} eq 'restricted')), + if_($self->need_rt2x00_iwpriv, + #- use iwpriv for WPA with rt2400/rt2500 drivers, they don't plan to support wpa_supplicant + WIRELESS_IWPRIV => qq(set AuthMode=WPAPSK +set EncrypType=TKIP +set SSID=$self->{access}{network}{essid} +set WPAPSK="$self->{access}{network}{key}" +set TxRate=0)), + (map { $_ => $self->{ifcfg}{$_} } + qw(WIRELESS_NWID WIRELESS_FREQ WIRELESS_SENS WIRELESS_RATE WIRELESS_RTS WIRELESS_FRAG WIRELESS_IWCONFIG WIRELESS_IWSPY), if_(!$self->need_rt2x00_iwpriv, 'WIRELESS_IWPRIV')), + }; + $self->SUPER::build_ifcfg_settings($settings); +} + +sub write_settings { + my ($self, $o_net, $o_modules_conf) = @_; + + wpa_supplicant_add_network($self->{access}{network}{essid}, $self->{access}{network}{encryption}, $self->{access}{network}{key}, $self->{access}{network}{mode}) if $self->need_wpa_supplicant; + + wlan_ng_configure($self->{access}{network}{essid}, $self->{access}{network}{key}, $self->get_interface, $self->get_driver) if $self->{thirdparty}{name} eq 'prism2'; + + my $network = $self->get_selected_network; + network::network::write_wireless_conf($_, $self->build_ifcfg_settings) foreach + grep { $_ } ($network ? $network->{ap} : ()), $self->{access}{network}{essid}; + + $self->SUPER::write_settings($o_net, $o_modules_conf); +} + +sub network_is_configured { + my ($self, $network) = @_; + if ($self->{control}{roaming}) { + return defined $network->{id}; + } else { + my $wireless_ifcfg = get_network_ifcfg($network->{ap}) || defined $network->{essid} && get_network_ifcfg($network->{essid}); + return $wireless_ifcfg; + } +} + +sub selected_network_is_configured { + my ($self) = @_; + + my $network = $self->get_selected_network or return; + $self->network_is_configured($network); +} + +sub prepare_connection { + my ($self) = @_; + if ($self->{control}{roaming}) { + #- this should be handled by the monitoring daemon instead + run_program::run('/usr/sbin/wpa_cli', 'reconfigure'); + sleep 2; + } +} + +sub connect { + my ($self, $_in, $net) = @_; + + $self->SUPER::connect; + + if ($self->{control}{roaming}) { + my $network = $self->get_selected_network; + if ($network && defined $network->{id}) { + eval { $net->{monitor}->select_network($network->{id}) }; + return !$@; + } + } +} + +sub get_status_message { + my ($self, $status) = @_; + my $interface = $self->get_interface; + my ($current_essid, $current_ap) = get_access_point($interface); + my $network = $current_essid || $current_ap && "[$current_ap]"; + { + link_up => N("Associated to wireless network \"%s\" on interface %s", $network, $interface), + link_down => N("Lost association to wireless network on interface %s", $interface), + }->{$status} || $self->SUPER::get_status_message($status); +} + + + +my $wpa_supplicant_conf = "/etc/wpa_supplicant.conf"; + +sub get_access_point { + my ($intf) = @_; + (chomp_(`/sbin/iwgetid -r $intf 2>/dev/null`), lc(chomp_(`/sbin/iwgetid -r -a $intf 2>/dev/null`))); +} + +sub is_old_rt2x00 { + my ($module) = @_; + member($module, qw(rt2400 rt2500 rt2570 rt61 rt73)); +} + +sub is_wpa_supplicant_blacklisted { + my ($module) = @_; + is_old_rt2x00($module); +} + +sub need_rt2x00_iwpriv { + my ($self) = @_; + is_old_rt2x00($self->get_driver) && $self->{access}{network}{encryption} eq 'wpa-psk'; +} + +sub get_hex_key { + my ($key) = @_; + if ($key =~ /^([[:xdigit:]]{4}[\:-]?)+[[:xdigit:]]{2,}$/) { + $key =~ s/[\:-]//g; + return lc($key); + } +} + +sub convert_wep_key_for_iwconfig { + #- 5 or 13 characters, consider the key as ASCII and prepend "s:" + #- else consider the key as hexadecimal, do not strip dashes + #- always quote the key as string + my ($real_key, $restricted) = @_; + my $key = get_hex_key($real_key) || "s:$real_key"; + $restricted ? "restricted $key" : "open $key"; +} + +sub convert_wep_key_for_wpa_supplicant { + my ($key) = @_; + get_hex_key($key) || qq("$key"); +} + +sub get_wep_key_from_iwconfig { + #- strip "s:" if the key is 5 or 13 characters (ASCII) + #- else the key as hexadecimal, do not modify + my ($key) = @_; + my ($mode, $real_key) = $key =~ /^(?:(open|restricted)\s+)?(.*)$/; + $real_key =~ s/^s://; + ($real_key, $mode eq 'restricted'); +} + +sub convert_key_for_wpa_supplicant { + my ($key) = @_; + length($key) == 64 && get_hex_key($key) || qq("$key"); +} + +#- FIXME: to be improved (quotes, comments) and moved in common files +sub wlan_ng_update_vars { + my ($file, $vars) = @_; + substInFile { + while (my ($key, $value) = each(%$vars)) { + s/^#?\Q$key\E=(?:"[^#]*"|[^#\s]*)(\s*#.*)?/$key=$value$1/ and delete $vars->{$key}; + } + $_ .= join('', map { "$_=$vars->{$_}\n" } keys %$vars) if eof; + } $file; +} + +sub wlan_ng_configure { + my ($essid, $key, $device, $module) = @_; + my $wlan_conf_file = "$::prefix/etc/wlan/wlan.conf"; + my @wlan_devices = split(/ /, (cat_($wlan_conf_file) =~ /^WLAN_DEVICES="(.*)"/m)[0]); + push @wlan_devices, $device unless member($device, @wlan_devices); + #- enable device and make it use the choosen ESSID + wlan_ng_update_vars($wlan_conf_file, + { + WLAN_DEVICES => qq("@wlan_devices"), + "SSID_$device" => qq("$essid"), + "ENABLE_$device" => "y" + }); + + my $wlan_ssid_file = "$::prefix/etc/wlan/wlancfg-$essid"; + #- copy default settings for this ESSID if config file does not exist + -f $wlan_ssid_file or cp_f("$::prefix/etc/wlan/wlancfg-DEFAULT", $wlan_ssid_file); + + #- enable/disable encryption + wlan_ng_update_vars($wlan_ssid_file, + { + (map { $_ => $key ? "true" : "false" } qw(lnxreq_hostWEPEncrypt lnxreq_hostWEPDecrypt dot11PrivacyInvoked dot11ExcludeUnencrypted)), + AuthType => $key ? qq("sharedkey") : qq("opensystem"), + if_($key, + dot11WEPDefaultKeyID => 0, + dot11WEPDefaultKey0 => qq("$key") + ) + }); + #- hide settings for non-root users + chmod 0600, $wlan_conf_file; + chmod 0600, $wlan_ssid_file; + + #- apply settings on wlan interface + require services; + services::restart($module eq 'prism2_cs' ? 'pcmcia' : 'wlan'); +} + +sub wpa_supplicant_get_driver { + my ($module) = @_; + $module =~ /^hostap_/ ? "hostap" : + $module eq "prism54" ? "prism54" : + $module =~ /^ath_/ ? "madwifi" : + $module =~ /^at76c50|atmel_/ ? "atmel" : + "wext"; +} + +sub wpa_supplicant_add_network { + my ($essid, $enc_mode, $key, $mode) = @_; + my $conf = wpa_supplicant_read_conf(); + my $network = { + ssid => qq("$essid"), + scan_ssid => 1, + }; + + if ($enc_mode eq 'wpa-psk') { + $network->{psk} = convert_key_for_wpa_supplicant($key); + } else { + $network->{key_mgmt} = 'NONE'; + $network->{mode} = to_bool($mode eq 'Ad-Hoc'); + if (member($enc_mode, qw(open restricted))) { + put_in_hash($network, { + wep_key0 => convert_wep_key_for_wpa_supplicant($key), + wep_tx_keyidx => 0, + auth_alg => $enc_mode eq 'restricted' ? 'SHARED' : 'OPEN', + }); + } + } + + @$conf = difference2($conf, [ wpa_supplicant_find_similar($conf, $network) ]); + push @$conf, $network; + wpa_supplicant_write_conf($conf); +} + +sub wpa_supplicant_find_similar { + my ($conf, $network) = @_; + grep { + my $current = $_; + any { exists $network->{$_} && $network->{$_} eq $current->{$_} } qw(ssid bssid); + } @$conf; +} + +sub wpa_supplicant_read_conf() { + my @conf; + my $network; + foreach (cat_($::prefix . $wpa_supplicant_conf)) { + if ($network) { + #- in a "network = {}" block + if (/^\s*(\w+)=(.*?)(?:\s*#.*)?$/) { + $network->{$1} = $2; + } elsif (/^\}/) { + #- end of network block + push @conf, $network; + undef $network; + } + } elsif (/^\s*network={/) { + #- beginning of a new network block + $network = {}; + } + } + \@conf; +} + +sub wpa_supplicant_write_conf { + my ($conf) = @_; + my $buf; + my @conf = @$conf; + my $network; + foreach (cat_($::prefix . $wpa_supplicant_conf)) { + if ($network) { + #- in a "network = {}" block + if (/^\s*(\w+)=(.*)$/) { + push @{$network->{entries}}, { key => $1, value => $2 }; + member($1, qw(ssid bssid)) and $network->{$1} = $2; + } elsif (/^\}/) { + #- end of network block, write it + $buf .= "network={$network->{comment}\n"; + + my $new_network = first(wpa_supplicant_find_similar(\@conf, $network)); + foreach (@{$network->{entries}}) { + my $key = $_->{key}; + if ($new_network) { + #- do not write entry if not provided in the new network + exists $new_network->{$key} or next; + #- update value from the new network + $_->{value} = delete $new_network->{$key}; + } + $buf .= " "; + $buf .= "$key=$_->{value}" if $key; + $buf .= "$_->{comment}\n"; + } + if ($new_network) { + #- write new keys + while (my ($key, $value) = each(%$new_network)) { + $buf .= " $key=$value\n"; + } + } + $buf .= "}\n"; + $new_network and @conf = grep { $_ != $new_network } @conf; + undef $network; + } else { + #- unrecognized, keep it anyway + push @{$network->{entries}}, { comment => $_ }; + } + } else { + if (/^\s*network={/) { + #- beginning of a new network block + $network = {}; + } else { + #- keep other options, comments + $buf .= $_; + } + } + } + + #- write remaining networks + foreach (@conf) { + $buf .= "\nnetwork={\n"; + while (my ($key, $value) = each(%$_)) { + $buf .= " $key=$value\n"; + } + $buf .= "}\n"; + } + + output($::prefix . $wpa_supplicant_conf, $buf); + #- hide keys for non-root users + chmod 0600, $::prefix . $wpa_supplicant_conf; +} + +1; diff --git a/lib/network/connection/xdsl.pm b/lib/network/connection/xdsl.pm new file mode 100644 index 0000000..337d4f7 --- /dev/null +++ b/lib/network/connection/xdsl.pm @@ -0,0 +1,375 @@ +package network::connection::xdsl; + +use base qw(network::connection::ppp); + +use strict; +use common; + +sub get_type_name() { N("DSL") } +sub get_type_icon() { 'xdsl-24.png' } + +sub get_devices() { + require detect_devices; + require network::connection::isdn; + require network::connection::ethernet; + my @usb_devices = detect_devices::get_xdsl_usb_devices(); + $_->{xdsl_type} = 'usb' foreach @usb_devices; + my @capi_devices = grep { $_->{driver} =~ /dsl/i } map { network::connection::isdn::find_capi_card($_) } network::connection::isdn->get_devices; + $_->{xdsl_type} = 'capi' foreach @capi_devices; + my @ethernet_devices = network::connection::ethernet::get_devices(); + $_->{xdsl_type} = 'ethernet' foreach @ethernet_devices; + @usb_devices, @capi_devices, @ethernet_devices; +} + +sub get_metric { 25 } +sub get_interface() { "ppp0" } + +my @non_ppp_protocols = qw(static dhcp); +sub uses_ppp { + my ($self) = @_; + !member($self->{protocol}, @non_ppp_protocols); +} + +my %protocol_settings = ( + pppoa => { + plugin => sub { + my ($self) = @_; + "pppoatm.so " . join('.', $self->{access}{peer}{vpi}, $self->{access}{peer}{vci}); + }, + }, + pppoe => { + pty => sub { + my ($self) = @_; + my $eth_interface = $self->network::connection::ethernet::get_interface; + qq("pppoe -m 1412 -I $eth_interface"); + }, + options => [ + qw(default-asyncmap noaccomp nobsdcomp novjccomp nodeflate), + "mru 1492", + "mtu 1492", + "lcp-echo-interval 20", + "lcp-echo-failure 3", + ], + }, + pptp => { + pty => qq("/usr/sbin/pptp 10.0.0.138 --nolaunchpppd"), + options => [ qw(noipdefault) ], + }, + capi => { + plugin => "capiplugin.so avmadsl", + options => [ + qw(ipcp-accept-remote ipcp-accept-local sync noipx), + "connect /bin/true", + "lcp-echo-interval 5", + "lcp-echo-failure 3", + "lcp-max-configure 50", + "lcp-max-terminate 2", + "mru 1492", + "mtu 1492" + ], + }, +); + +my @thirdparty_settings = ( + { + matching => 'speedtch', + description => N_("Alcatel speedtouch USB modem"), + url => "http://www.speedtouch.com/supuser.htm", + name => 'speedtouch', + firmware => + { + package => 'speedtouch-firmware', + test_file => 'speedtch-*.bin*', + extract => { + name => 'speedtouch-firmware-extractor', + test_file => '/usr/sbin/firmware-extractor', + windows_source => 'alcaudsl.sys', + floppy_source => 'mgmt*.o', + default_source => '/usr/share/speedtouch/mgmt.o', + run => sub { + my ($file) = @_; + run_program::raw({ root => $::prefix, chdir => $network::thirdparty::firmware_directory }, + '/usr/sbin/firmware-extractor', $file); + }, + }, + }, + links => 'http://linux-usb.sourceforge.net/SpeedTouch/mandrake/index.html', + ppp => { + options => [ qw(noaccomp sync) ], + }, + }, + + { + name => 'eciadsl', + explanations => N_("The ECI Hi-Focus modem cannot be supported due to binary driver distribution problem. + +You can find a driver on http://eciadsl.flashtux.org/"), + no_club => 1, + tools => { + test_file => '/usr/sbin/pppoeci', + }, + ppp => { + options => [ + qw(noipdefault noaccomp sync), + "linkname eciadsl", + "lcp-echo-interval 0", + ], + protocols => { + pppoe => { + pty => sub { + my ($self) = @_; + qq("/usr/bin/pppoeci -v 1 -vpi $self->{access}{peer}{vpi} -vci $self->{access}{peer}{vci}"); + }, + }, + }, + }, + }, + + { + matching => [ 'ueagle-atm', 'eagle-usb' ], + description => 'Eagle chipset (from Analog Devices), e.g. Sagem F@st 800/840/908', + url => 'http://www.eagle-usb.org/', + name => 'ueagle', + firmware => { + test_file => 'ueagle-atm/eagle*.fw', + }, + links => 'http://atm.eagle-usb.org/wakka.php?wiki=UeagleAtmDoc', + }, + + { + matching => qr/^unicorn_.*_atm$/, + description => 'Bewan Adsl (Unicorn)', + url => 'http://www.bewan.com/bewan/users/downloads/', + name => 'unicorn', + kernel_module => { + test_file => 'unicorn_.*_atm', + }, + tools => { + optional => 1, + test_file => '/usr/bin/bewan_adsl_status', + }, + sleep => 10, + ppp => { + options => [ + qw(default-asyncmap hide-password noaccomp nobsdcomp nodeflate novjccomp sync), + "lcp-echo-interval 20", + "lcp-echo-failure 3", + ], + }, + }, +); + +sub get_thirdparty_settings() { + \@thirdparty_settings; +} + +sub get_providers { + my ($self) = @_; + require network::connection::providers::xdsl; + if_($self->{device}{xdsl_type} ne 'capi', \%network::connection::providers::xdsl::data, '|'); +} + +sub get_protocols { + my ($self) = @_; + $self->{device}{xdsl_type} eq 'capi' ? + { + capi => N("DSL over CAPI"), + } : + { + dhcp => N("Dynamic Host Configuration Protocol (DHCP)"), + static => N("Manual TCP/IP configuration"), + pptp => N("Point to Point Tunneling Protocol (PPTP)"), + pppoe => N("PPP over Ethernet (PPPoE)"), + pppoa => N("PPP over ATM (PPPoA)"), + }; +} + +sub guess_protocol { + my ($self, $net) = @_; + $self->{protocol} = $self->{provider} && $self->{provider}{method}; + if ($self->{device}{xdsl_type} eq 'capi') { + $self->{protocol} = 'capi'; + } elsif ($self->{device}{xdsl_type} eq 'ethernet') { + require network::connection::ethernet; + my $interface = $self->network::connection::ethernet::get_interface; + if (my $ifcfg = $net->{ifcfg}{$interface}) { + $self->{protocol} = $ifcfg->{BOOTPROTO} if member($ifcfg->{BOOTPROTO}, @non_ppp_protocols); + $self->{protocol} ||= 'dhcp'; + #- pppoa shouldn't be selected by default for ethernet devices, fallback on pppoe + $self->{protocol} = 'pppoe' if $self->{protocol} eq 'pppoa'; + } + } +} + +sub guess_access_settings { + my ($self) = @_; + require network::adsl; + my $probe = {}; + network::adsl::adsl_probe_info($probe); + $self->{access}{login} = $probe->{adsl}{login}; + $self->{access}{password} = $probe->{adsl}{passwd}; + $self->{access}{peer}{$_} = $probe->{adsl}{$_} foreach qw(vpi vci); + if ($self->{provider}) { + $self->{access}{peer}{$_} = hex($self->{provider}{$_}) foreach qw(vpi vci); + } +} + +sub get_access_settings { + my ($self) = @_; + + [ + @{$self->network::connection::ppp::get_access_settings}, + if_(member($self->{protocol}, qw(pppoa pppoe)), + { label => N("Virtual Path ID (VPI):"), val => \$self->{access}{peer}{vpi}, advanced => 1 }, + { label => N("Virtual Circuit ID (VCI):"), val => \$self->{access}{peer}{vci}, advanced => 1 } + ), + ]; +} + +sub get_peer_default_options { + my ($self) = @_; + $self->network::connection::ppp::get_peer_default_options, + qw(lock persist nopcomp noccp novj), + "kdebug 1", + "holdoff 4", + "maxfail 25"; +} + +sub build_peer { + my ($self) = @_; + my $may_call = sub { ref $_[0] eq 'CODE' ? $_[0]->($self) : $_[0] }; + my @ppp_fields = qw(plugin pty); + my @ppp_options; + if ($self->{thirdparty}) { + foreach my $settings (grep { $_ } $self->{thirdparty}{ppp}{protocols}{$self->{protocol}}, $self->{thirdparty}{ppp}) { + @ppp_options = @{$settings->{options}} if $settings->{options}; + foreach (@ppp_fields) { + $self->{access}{peer}{$_} ||= $may_call->($settings->{$_}) if defined $settings->{$_}; + } + } + } + if (my $generic_settings = $protocol_settings{$self->{protocol}}) { + @ppp_options = @{$generic_settings->{options} || []} if !@ppp_options; + foreach (@ppp_fields) { + $self->{access}{peer}{$_} ||= $may_call->($generic_settings->{$_}) if defined $generic_settings->{$_}; + } + } + + @ppp_options, #- write them before pty/plugin stuff + $self->network::connection::ppp::build_peer; +} + +sub write_settings { + my ($self, $net) = @_; + + if ($self->{device}{xdsl_type} eq 'ethernet' && $self->{protocol} eq 'pppoe') { + my $interface = $self->network::connection::ethernet::get_interface; + $net->{ifcfg}{$interface} = { + DEVICE => $interface, + BOOTPROTO => 'none', + NETMASK => '255.255.255.0', + NETWORK => '10.0.0.0', + BROADCAST => '10.0.0.255', + MII_NOT_SUPPORTED => 'yes', + ONBOOT => 'yes', + }; + } + + if ($self->{protocol} eq 'capi') { + require network::connection::isdn; + network::connection::isdn::write_capi_conf($self->{device}); + } + + #- TODO: add "options ueagle-atm cmv_file= $net->{adsl}{cmv}.bin" in /etc/modprobe.d/ueagle-atm + # if ($self->get_driver eq 'ueagle-atm') { ... } + + if ($self->uses_ppp) { + $self->network::connection::ppp::write_settings; + } else { + $self->network::connection::write_settings; + } +} + +sub build_ifcfg_settings { + my ($self) = @_; + my $settings = { + if_($self->uses_ppp, TYPE => 'ADSL'), + }; + if ($self->{device}{xdsl_type} eq 'usb' && !$self->uses_ppp) { + #- use ATMARP with the atm0 interface + put_in_hash({ + DEVICE => "atm0", + ATM_ADDR => join('.', @{$self->{access}{peer}}{qw(vpi vci)}), + MII_NOT_SUPPORTED => "yes", + }, $settings); + } + $self->network::connection::build_ifcfg_settings($settings); +} + +sub unload_connection { + my ($self) = @_; + require network::connection::isdn; + network::connection::isdn::unload_connection($self->{device}) if $self->{protocol} eq 'capi'; +} + +sub install_packages { + my ($self, $in) = @_; + my $packages = { + pppoa => [ qw(ppp-pppoatm) ], + pppoe => [ qw(rp-pppoe) ], + pptp => [ qw(pptp-linux) ], + capi => [ qw(ppp) ], + }->{$self->{protocol}}; + if ($packages && !$in->do_pkgs->install(@$packages)) { + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", @$packages)); + return; + } + if ($self->{protocol} eq 'capi') { + require network::connection::isdn; + network::connection::isdn::install_packages($self->{device}, $in); + $in->do_pkgs->ensure_is_installed_if_available("drdsl", "/usr/sbin/drdsl"); + } + 1; +} + +sub prepare_connection { + my ($self) = @_; + + if ($::isInstall) { + #- load modules that are not automatically loaded during install + my @modules = qw(ppp_synctty ppp_async ppp_generic n_hdlc); #- required for pppoe/pptp connections + push @modules, 'pppoatm' if $self->{protocol} eq 'pppoa'; + foreach (@modules) { + eval { modules::load($_) } or log::l("failed to load $_ module: $@"); + } + } + + if ($self->{protocol} eq 'capi') { + require network::connection::isdn; + network::connection::isdn::prepare_connection($self->{device}); + require run_program; + run_program::rooted($::prefix, "/usr/sbin/drdsl"); + } + + 1; +} + +sub connect { + my ($self) = @_; + if ($self->{device}{xdsl_type} eq 'ethernet') { + require network::tools; + network::tools::start_interface($self->network::connection::ethernet::get_interface, 0); + } + $self->network::connection::connect; +} + +sub disconnect { + my ($self) = @_; + $self->network::connection::disconnect; + if ($self->{device}{xdsl_type} eq 'ethernet') { + require network::tools; + network::tools::stop_interface($self->network::connection::ethernet::get_interface, 0); + } +} + +1; diff --git a/lib/network/drakfirewall.pm b/lib/network/drakfirewall.pm index e67da22..600a5d3 100644 --- a/lib/network/drakfirewall.pm +++ b/lib/network/drakfirewall.pm @@ -137,7 +137,7 @@ sub get_ports() { } sub set_ports { - my ($do_pkgs, $disabled, $ports, $o_in) = @_; + my ($do_pkgs, $disabled, $ports, $log_net_drop, $o_in) = @_; my $shorewall = network::shorewall::read($o_in) or return; @@ -146,8 +146,9 @@ sub set_ports { $shorewall->{disabled} = $disabled; $shorewall->{ports} = $ports; + $shorewall->{log_net_drop} = $log_net_drop; log::l($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports"); - network::shorewall::write($shorewall); + network::shorewall::write($shorewall, $o_in); } } @@ -160,15 +161,15 @@ sub get_conf { if ($o_ports) { $disabled, from_ports($o_ports); } elsif (my $shorewall = network::shorewall::read()) { - $shorewall->{disabled}, from_ports($shorewall->{ports}); + $shorewall->{disabled}, from_ports($shorewall->{ports}), $shorewall->{log_net_drop}; } else { - $in->ask_okcancel('', N("drakfirewall configurator + $in->ask_okcancel(N("Firewall configuration"), N("drakfirewall configurator This configures a personal firewall for this Mandriva Linux machine. For a powerful and dedicated firewall solution, please look to the specialized Mandriva Security Firewall distribution."), 1) or return; - $in->ask_okcancel('', N("drakfirewall configurator + $in->ask_okcancel(N("Firewall configuration"), N("drakfirewall configurator Make sure you have configured your Network/Internet access with drakconnect before going any further."), 1) or return; @@ -178,7 +179,7 @@ drakconnect before going any further."), 1) or return; } sub choose_allowed_services { - my ($in, $disabled, $servers, $unlisted) = @_; + my ($in, $disabled, $servers, $unlisted, $log_net_drop) = @_; $_->{on} = 0 foreach @all_servers; $_->{on} = 1 foreach @$servers; @@ -206,10 +207,11 @@ You can also give a range of ports (eg: 24300:24350/udp)", $invalid_port)); [ { text => N("Everything (no firewall)"), val => \$disabled, type => 'bool' }, (map { { text => translate($_->{name}), val => \$_->{on}, type => 'bool', disabled => sub { $disabled } } } @l), - { label => N("Other ports"), val => \$unlisted, advanced => 1, disabled => sub { $disabled } } + { label => N("Other ports"), val => \$unlisted, advanced => 1, disabled => sub { $disabled } }, + { text => N("Log firewall messages in system logs"), val => \$log_net_drop, type => 'bool', advanced => 1, disabled => sub { $disabled } }, ]) or return; - $disabled, [ grep { $_->{on} } @l ], $unlisted; + $disabled, [ grep { $_->{on} } @l ], $unlisted, $log_net_drop; } sub set_ifw { @@ -218,16 +220,16 @@ sub set_ifw { $do_pkgs->ensure_is_installed('mandi-ifw', '/etc/ifw/start', $::isInstall) or return; my $ports_by_proto = network::shorewall::ports_by_proto($ports); - output_with_perm("$::prefix/etc/ifw/rules", 0644, map { "$_\n" } ( - (map { "source /etc/ifw/rules.d/$_" } @$rules), + output_with_perm("$::prefix/etc/ifw/rules", 0644, + (map { "source /etc/ifw/rules.d/$_\n" } @$rules), map { my $proto = $_; map { my $multiport = /:/ && " -m multiport"; "iptables -A Ifw -m state --state NEW -p $proto$multiport --dport $_ -j IFWLOG --log-prefix NEW\n"; } @{$ports_by_proto->{$proto}}; - } keys %$ports_by_proto, - )); + } intersection([ qw(tcp udp) ], [ keys %$ports_by_proto ]), + ); } my $set_in_file = sub { @@ -252,7 +254,7 @@ sub choose_watched_services { messages => N("Interactive Firewall") . "\n\n" . N("You can be warned when someone accesses to a service or tries to intrude into your computer. -Please select which network activity should be watched."), +Please select which network activities should be watched."), title => N("Interactive Firewall"), }, [ @@ -270,14 +272,14 @@ Please select which network activity should be watched."), sub main { my ($in, $disabled) = @_; - ($disabled, my $servers, my $unlisted) = get_conf($in, $disabled) or return; + ($disabled, my $servers, my $unlisted, my $log_net_drop) = get_conf($in, $disabled) or return; - ($disabled, $servers, $unlisted) = choose_allowed_services($in, $disabled, $servers, $unlisted) or return; + ($disabled, $servers, $unlisted, $log_net_drop) = choose_allowed_services($in, $disabled, $servers, $unlisted, $log_net_drop) or return; choose_watched_services($in, $servers, $unlisted) unless $disabled; my $ports = to_ports($servers, $unlisted); - set_ports($in->do_pkgs, $disabled, $ports, $in) or return; + set_ports($in->do_pkgs, $disabled, $ports, $log_net_drop, $in) or return; ($disabled, $ports); } diff --git a/lib/network/drakvpn.pm b/lib/network/drakvpn.pm new file mode 100644 index 0000000..158b40c --- /dev/null +++ b/lib/network/drakvpn.pm @@ -0,0 +1,120 @@ +package network::drakvpn; + +=head1 NAME + +network::drakvpn - Interactive VPN configuration + +=head1 SYNOPSIS + + use interactive; + use network::drakvpn; + + my $in = 'interactive'->vnew('su'); + network::drakvpn::create_connection($in); + +=cut + +use strict; +use common; + +use network::vpn; + +sub create_connection { + my ($in) = @_; + my $vpn_type; + my $vpn_connection; + my $new_name; + require wizards; + my $wiz = wizards->new({ + defaultimage => "drakvpn", + name => N("VPN configuration"), + pages => { + welcome => { + if_(!$::isInstall, no_back => 1), + name => N("Choose the VPN type"), + data => [ { + val => \$vpn_type, type => 'list', + list => [ sort { $a->get_description cmp $b->get_description } network::vpn::list_types ], + format => sub { $_[0] && $_[0]->get_description }, + allow_empty_list => 1, + } ], + complete => sub { + $vpn_type or return 1; + my @packages = $vpn_type->get_packages; + if (@packages && !$in->do_pkgs->install(@packages)) { + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); + return 1; + } + if ($vpn_type->can('prepare')) { + my $wait = $in->wait_message('', N("Initializing tools and detecting devices for %s...", $vpn_type->get_type)); + if (!$vpn_type->prepare) { + undef $wait; + $in->ask_warn(N("Error"), N("Unable to initialize %s connection type!", $vpn_type->get_type)); + return 1; + } + } + }, + next => "vpn_name", + }, + vpn_name => { + name => N("Please select an existing VPN connection or enter a new name."), + data => sub { [ + { label => N("VPN connection"), val => \$vpn_connection, type => 'list', + list => [ $vpn_type->get_configured_connections, '' ], + format => sub { $_[0] ? $_[0]{name} : N("Configure a new connection...") }, + gtk => { use_boxradio => 1 } }, + { label => N("New name"), val => \$new_name, disabled => sub { $vpn_connection } }, + ] }, + complete => sub { + if (!$vpn_connection && !$new_name) { + $in->ask_warn(N("Warning"), N("You must select an existing connection or enter a new name.")); + 1; + } + }, + post => sub { + $vpn_connection ||= $vpn_type->new($new_name); + $vpn_connection->read_config; + $vpn_connection->can('get_key_settings') ? "vpn_key_settings" : "vpn_settings"; + }, + }, + vpn_key_settings => { + name => N("Please enter the required key(s)"), + data => sub { $vpn_connection->get_key_settings }, + next => "vpn_settings", + }, + vpn_settings => { + name => N("Please enter the settings of your VPN connection"), + data => sub { $vpn_connection->get_settings }, + post => sub { + $vpn_connection->write_config; + "connect"; + }, + }, + connect => { + name => N("Do you want to start the connection now?"), + type => "yesorno", + post => sub { + my ($connect) = @_; + if ($connect) { + $vpn_connection->is_started and $vpn_connection->stop; + $vpn_connection->start($in) or $in->ask_warn(N("Warning"), N("Connection failed.")); + } + require network::network; + network::network::reload_net_applet(); + "end"; + }, + }, + end => { + name => N("The VPN connection is now configured. + +This VPN connection can be automatically started together with a network connection. +It can be done by reconfiguring the network connection and selecting this VPN connection. +"), + end => 1, + }, + }, + }); + $wiz->process($in); +} + +1; diff --git a/lib/network/ethernet.pm b/lib/network/ethernet.pm deleted file mode 100644 index c97f45f..0000000 --- a/lib/network/ethernet.pm +++ /dev/null @@ -1,162 +0,0 @@ -package network::ethernet; # $Id$ - -use c; -use detect_devices; -use common; -use run_program; - -our @dhcp_clients = qw(dhclient dhcpcd pump dhcpxd); - -sub install_dhcp_client { - my ($in, $client) = @_; - my %packages = ( - "dhclient" => "dhcp-client", - ); - #- use default dhcp client if none is provided - $client ||= $dhcp_clients[0]; - $client = $packages{$client} if exists $packages{$client}; - $in->do_pkgs->install($client); -} - -sub mapIntfToDevice { - my ($interface) = @_; - my $hw_addr = c::getHwIDs($interface); - return {} if $hw_addr =~ /^usb/; - my ($bus, $slot, $func) = map { hex($_) } ($hw_addr =~ /([0-9a-f]+):([0-9a-f]+)\.([0-9a-f]+)/); - $hw_addr && (every { defined $_ } $bus, $slot, $func) ? - grep { $_->{pci_bus} == $bus && $_->{pci_device} == $slot && $_->{pci_function} == $func } detect_devices::probeall() : {}; -} - - -# return list of [ intf_name, module, device_description ] tuples such as: -# [ "eth0", "3c59x", "3Com Corporation|3c905C-TX [Fast Etherlink]" ] -# -# this function try several method in order to get interface's driver and description in order to support both: -# - hotplug managed devices (USB, firewire) -# - special interfaces (IP aliasing, VLAN) -sub get_eth_cards { - my ($modules_conf) = @_; - my @all_cards = detect_devices::getNet(); - - my @devs = detect_devices::pcmcia_probe(); - my $saved_driver; - # compute device description and return (interface, driver, description) tuples: - return map { - my $interface = $_; - my $description; - # 1) get interface's driver through ETHTOOL ioctl: - my ($a, $detected_through_ethtool); - $a = c::getNetDriver($interface); - if ($a) { - $detected_through_ethtool = 1; - } else { - # 2) get interface's driver through module aliases: - $a = $modules_conf->get_alias($interface); - } - - # workaround buggy drivers that returns a bogus driver name for the GDRVINFO command of the ETHTOOL ioctl: - my %fixes = ( - "p80211_prism2_cs" => 'prism2_cs', - "p80211_prism2_pci" => 'prism2_pci', - "p80211_prism2_usb" => 'prism2_usb', - "ip1394" => "eth1394", - "DL2K" => "dl2k", - "orinoco" => undef, #- should be orinoco_{cs,nortel,pci,plx,tmd} - "hostap" => undef, #- should be hostap_{cs,pci,plx} - ); - if (exists $fixes{$a}) { - $a = $fixes{$a}; - $a or undef $detected_through_ethtool; - } - - # 3) try to match a PCMCIA device for device description: - if (my $b = find { $_->{device} eq $interface } @devs) { # PCMCIA case - $a = $b->{driver}; - $description = $b->{description}; - } else { - # 4) try to lookup a device by hardware address for device description: - # maybe should have we try sysfs first for robustness? - ($description) = (mapIntfToDevice($interface))[0]->{description}; - } - # 5) try to match a device through sysfs for driver & device description: - # (eg: ipw2100 driver for intel centrino do not support ETHTOOL) - if (!$description || !$a) { - my $dev_path = "/sys/class/net/$interface/device"; - my $drv = readlink("$dev_path/driver"); - if ($drv && $drv =~ s!.*/!!) { - $a = $drv unless $detected_through_ethtool; - my $sysfs_fields = detect_devices::get_sysfs_device_id_map($dev_path); - my %l = map { $_ => hex(chomp_(cat_("$dev_path/" . $sysfs_fields->{$_}))) } keys %$sysfs_fields; - my @cards = grep { my $dev = $_; every { $dev->{$_} eq $l{$_} } keys %l } detect_devices::probeall(); - $description ||= $cards[0]{description} if @cards == 1; - } elsif (!$a && -e "/sys/class/net/$interface/wireless") { - # probably a rt2400/rt2500 device (PCI or PCMCIA CardBus) or zd1201 (USB) - # these broken drivers don't create the "device" link - # try to see if rt2400/rt2500/zd1201 is loaded, and assume current wireless device uses it - # FIXME: remove this code as soon as the drivers are fixed - $a = find { -e "/sys/bus/pci/drivers/$_" } qw(rt2400 rt2500); - $a ||= find { -e "/sys/bus/usb/drivers/$_" } qw(zd1201); - } - } - # 6) try to match a device by driver for device description: - # (eg: madwifi, ndiswrapper, ...) - if (!$description) { - my @cards = grep { $_->{driver} eq ($a || $saved_driver) } detect_devices::probeall(); - $description = $cards[0]{description} if @cards == 1; - } - $a and $saved_driver = $a; # handle multiple cards managed by the same driver - [ $interface, $saved_driver, if_($description, $description) ]; - } @all_cards; -} - -sub get_eth_cards_names { - my (@all_cards) = @_; - map { $_->[0] => join(': ', $_->[0], $_->[2]) } @all_cards; -} - -#- returns (link_type, mac_address) -sub get_eth_card_mac_address { - my ($intf) = @_; - #- don't look for 6 bytes addresses only because of various non-standard MAC addresses - `$::prefix/sbin/ip -o link show $intf 2>/dev/null` =~ m|.*link/(\S+)\s((?:[0-9a-f]{2}:?)+)\s|; -} - -#- write interfaces MAC address in iftab -sub update_iftab() { - #- skip aliases interfaces - foreach my $intf (grep { !/:\d+$/ } detect_devices::getNet()) { - my ($link_type, $mac_address) = get_eth_card_mac_address($intf) or next; - #- do not write zeroed MAC addresses in iftab, it confuses ifrename - $mac_address =~ /^[0:]+$/ and next; - # ifrename supports alsa IEEE1394, EUI64 and IRDA - member($link_type, 'ether', 'ieee1394', 'irda', '[27]') or next; - substInFile { - s/^$intf\s+.*\n//; - s/^.*\s+$mac_address\n//; - $_ .= qq($intf mac $mac_address\n) if eof; - } "$::prefix/etc/iftab"; - } -} - -# automatic net aliases configuration -sub configure_eth_aliases { - my ($modules_conf) = @_; - my @pcmcia_interfaces = map { $_->{device} } detect_devices::pcmcia_probe(); - foreach my $card (get_eth_cards($modules_conf)) { - if (member($card->[0], @pcmcia_interfaces)) { - #- do not write aliases for pcmcia cards, or cardmgr will not be loaded - $modules_conf->remove_alias($card->[0]); - } else { - $modules_conf->set_alias($card->[0], $card->[1]); - } - } - $::isStandalone and $modules_conf->write; - update_iftab(); -} - -sub is_ifplugd_blacklisted { - my ($module) = @_; - member($module, qw(forcedeth via-velocity)); -} - -1; diff --git a/lib/network/ifw.pm b/lib/network/ifw.pm index 40ff0ac..44f58da 100644 --- a/lib/network/ifw.pm +++ b/lib/network/ifw.pm @@ -18,7 +18,7 @@ sub new { "com.mandriva.monitoring", "/com/mandriva/monitoring/ifw", "com.mandriva.monitoring.ifw"); - dbus_object::set_gtk2_watch($o); + $o->set_gtk2_watch; $o; } @@ -138,4 +138,18 @@ sub attack_to_hash { $attack; } +sub parse_listen_message { + my ($args) = @_; + my $listen = { mapn { $_[0] => $_[1] } [ 'program', 'port' ], $args }; + $listen->{port} = unpack('S', pack('n', $listen->{port})); + $listen->{service} = get_service($listen->{port}); + $listen->{message} = N("The \"%s\" application is trying to make a service (%s) available to the network.", + $listen->{program}, + $listen->{service} ne $listen->{port} ? $listen->{service} : + #-PO: this should be kept lowercase since the expression is meant to be used between brackets + N("port %d", $listen->{port}), + ); + $listen; +} + 1; diff --git a/lib/network/invictus.pm b/lib/network/invictus.pm new file mode 100644 index 0000000..91806d5 --- /dev/null +++ b/lib/network/invictus.pm @@ -0,0 +1,30 @@ +package network::invictus; + +use MDK::Common; + +my $ucarp_d = "/etc/ucarp.d"; +my $ct_sync_config = "/etc/sysconfig/ct_sync"; + +sub read_config { + my ($invictus) = @_; + foreach (all($::prefix . $ucarp_d)) { + $invictus->{ucarp}{$_} = +{ getVarsFromSh($::prefix . $ucarp_d . '/' . $_) }; + } + $invictus->{ct_sync} = +{ getVarsFromSh($::prefix . $ct_sync_config) }; + $invictus->{ct_sync}{CMARKBIT} ||= 30; +} + +sub write_config { + my ($invictus) = @_; + mkdir_p($::prefix . $ucarp_d); + foreach (keys %{$invictus->{ucarp}}) { + $invictus->{ucarp}{$_}{UPSCRIPT} ||= '/usr/share/invictus-firewall/ucarp-up.sh'; + $invictus->{ucarp}{$_}{DOWNSCRIPT} ||= '/usr/share/invictus-firewall/ucarp-down.sh'; + setVarsInShMode($::prefix . $ucarp_d . '/' . $_, 0600, $invictus->{ucarp}{$_}, + qw(INTERFACE SRCIP VIRTIP VHID PASSWORD TAKEOVER UPSCRIPT DOWNSCRIPT)); + } + setVarsInSh($::prefix . $ct_sync_config, $invictus->{ct_sync}, + qw(ENABLE INTERFACE CMARKBIT)); +} + +1; diff --git a/lib/network/ipsec.pm b/lib/network/ipsec.pm index c0ca768..846b07a 100644 --- a/lib/network/ipsec.pm +++ b/lib/network/ipsec.pm @@ -9,23 +9,7 @@ use log; #- debugg functions ---------- sub recreate_ipsec_conf { - my ($ipsec, $kernel_version) = @_; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - foreach my $key1 (ikeys %$ipsec) { - print "$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; - foreach my $key2 (ikeys %{$ipsec->{$key1}}) { - if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { - print "\t$ipsec->{$key1}{$key2}[0]\n"; - } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(conn|config|version)/) { - print "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; - } else { - print "\t$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n"; - } - } - } - } else { - #- kernel 2.6 part ------------------------------- + my ($ipsec) = @_; foreach my $key1 (ikeys %$ipsec) { if (! $ipsec->{$key1}{command}) { print "$ipsec->{$key1}\n"; @@ -43,7 +27,6 @@ sub recreate_ipsec_conf { $ipsec->{$key1}{level} . ";\n"; } } - } } sub recreate_racoon_conf { @@ -479,7 +462,7 @@ sub remove_section_racoon_conf { #------------------------------------------------------------------- sub read_ipsec_conf { - my ($ipsec_conf, $kernel_version) = @_; + my ($ipsec_conf) = @_; my %conf; my $nb = 0; #total number my $i = 0; #nb within a connexion @@ -487,48 +470,6 @@ sub read_ipsec_conf { my $line = ""; my @line1; local $_; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - open(my $LIST, "< $ipsec_conf"); #or die "Can not open the $ipsec_conf file for reading"; - while (<$LIST>) { - chomp($_); - $line = $_; - $line =~ s/^\s+//; - if (!$line) { - $nb++; - put_in_hash(\%conf, { $nb => $line }); - $in_a_conn = "n"; - } elsif ($line =~ /^#/) { - if ($in_a_conn eq "y") { - put_in_hash($conf{$nb} ||= {}, { $i => [$line] }); - $i++; - } else { - $nb++; - put_in_hash(\%conf, { $nb => $line }); - $in_a_conn = "n"; - } - } elsif ($line =~ /^conn|^config|^version/ && $in_a_conn eq "n") { - @line1 = split /\s+/,$line; - $i=1; - $nb++; - put_in_hash($conf{$nb} ||= {}, { $i => [$line1[0], $line1[1]] }); - $in_a_conn = "y" if $line !~ /^version/; - $i++; - } elsif ($line =~ /^conn|^config|^version/ && $in_a_conn eq "y") { - @line1 = split /\s+/,$line; - $i=1; - $nb++; - put_in_hash($conf{$nb} ||= {}, { $i => [$line1[0], $line1[1]] }); - $i++; - } else { - @line1 = split /=/,$line; - put_in_hash($conf{$nb} ||= {}, { $i => [$line1[0], $line1[1]] }); - $i++; - } - } - - } else { - #- kernel 2.6 part ------------------------------- my @mylist; my $myline = ""; open(my $LIST, "< $ipsec_conf"); #or die "Can not open the $ipsec_conf file for reading"; @@ -561,31 +502,12 @@ sub read_ipsec_conf { put_in_hash(\%conf, { $nb => $myline }); } } - - } \%conf; } sub write_ipsec_conf { - my ($ipsec_conf, $ipsec, $kernel_version) = @_; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - open(my $ADD, "> $ipsec_conf") or die "Can not open the $ipsec_conf file for writing"; - foreach my $key1 (ikeys %$ipsec) { - print $ADD "$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; - foreach my $key2 (ikeys %{$ipsec->{$key1}}) { - if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { - print $ADD "\t$ipsec->{$key1}{$key2}[0]\n"; - } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(^conn|^config|^version)/) { - print $ADD "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; - } else { - print $ADD "\t$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n" if $ipsec->{$key1}{$key2}[0] && $ipsec->{$key1}{$key2}[1]; - } - } - } - } else { - #- kernel 2.6 part ------------------------------- + my ($ipsec_conf, $ipsec) = @_; my $display = ""; foreach my $key1 (ikeys %$ipsec) { if (! $ipsec->{$key1}{command}) { @@ -606,30 +528,12 @@ sub write_ipsec_conf { } open(my $ADD, "> $ipsec_conf") or die "Can not open the $ipsec_conf file for writing"; print $ADD $display; - } } sub display_ipsec_conf { - my ($ipsec, $kernel_version) = @_; + my ($ipsec) = @_; my $display = ""; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - foreach my $key1 (ikeys %$ipsec) { - $display .= "$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; - foreach my $key2 (ikeys %{$ipsec->{$key1}}) { - if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { - $display .= "\t$ipsec->{$key1}{$key2}[0]\n"; - } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(^conn|^config|^version)/) { - $display .= "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; - } else { - $display .= "\t$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n"; - } - } - } - - } else { - #- kernel 2.6 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { if (! $ipsec->{$key1}{command}) { $display .= "$ipsec->{$key1}\n"; @@ -648,54 +552,26 @@ sub display_ipsec_conf { } } - } - $display; } sub get_section_names_ipsec_conf { - my ($ipsec, $kernel_version) = @_; + my ($ipsec) = @_; my @section_names; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - foreach my $key1 (ikeys %$ipsec) { - foreach my $key2 (ikeys %{$ipsec->{$key1}}) { - if ($ipsec->{$key1}{$key2}[0] =~ m/(^conn|^config|^version)/) { - push(@section_names, "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]"); - } - } - } - - } else { - #- kernel 2.6 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { if ($ipsec->{$key1}{command} =~ m/(^spdadd)/) { push(@section_names, "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"); } } - } @section_names; } sub remove_section_ipsec_conf { - my ($section_name, $ipsec, $kernel_version) = @_; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - foreach my $key1 (ikeys %$ipsec) { - if (find { - my $s = $ipsec->{$key1}{$_}[0]; - $s !~ /^#/ && $s =~ m/(^conn|^config|^version)/ && - $section_name eq "$s $ipsec->{$key1}{$_}[1]"; - } ikeys %{$ipsec->{$key1}}) { - delete $ipsec->{$key1}; - } - } - } else { - #- kernel 2.6 part ------------------------------- + my ($section_name, $ipsec) = @_; foreach my $key1 (ikeys %$ipsec) { if (find { my $s = "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"; @@ -705,7 +581,6 @@ sub remove_section_ipsec_conf { delete $ipsec->{$key1}; } } - } } sub add_section_ipsec_conf { @@ -715,20 +590,7 @@ sub add_section_ipsec_conf { } sub already_existing_section_ipsec_conf { - my ($section_name, $ipsec, $kernel_version) = @_; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - foreach my $key1 (ikeys %$ipsec) { - if (find { - my $s = $ipsec->{$key1}{$_}[0]; - $s !~ /^#/ && $s =~ m/(^conn|^config|^version)/ && - $section_name eq "$s $ipsec->{$key1}{$_}[1]"; - } ikeys %{$ipsec->{$key1}}) { - return "already existing"; - } - } - } else { - #- kernel 2.6 part ------------------------------- + my ($section_name, $ipsec) = @_; foreach my $key1 (ikeys %$ipsec) { if (find { my $s = "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"; @@ -738,35 +600,12 @@ sub already_existing_section_ipsec_conf { return "already existing"; } } - } return "no"; } -#- returns the reference to the dynamical list for editing -sub dynamic_list { - my ($number, $ipsec) = @_; - my @list = map { { label => $ipsec->{$number}{$_}[0] . "=", - val => \$ipsec->{$number}{$_}[1] } } ikeys %{$ipsec->{$number}}; - - @list; -} - #- returns the hash key number of $section_name sub matched_section_key_number_ipsec_conf { - my ($section_name, $ipsec, $kernel_version) = @_; - if ($kernel_version < 2.5) { - #- kernel 2.4 part ------------------------------- - foreach my $key1 (ikeys %$ipsec) { - if (find { - my $s = $ipsec->{$key1}{$_}[0]; - $s !~ /^#/ && $s =~ m/(^conn|^config|^version)/ && - $section_name eq "$s $ipsec->{$key1}{$_}[1]"; - } ikeys %{$ipsec->{$key1}}) { - return $key1; - } - } - } else { - #- kernel 2.6 part ------------------------------- + my ($section_name, $ipsec) = @_; foreach my $key1 (ikeys %$ipsec) { if (find { my $s = "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"; @@ -776,6 +615,5 @@ sub matched_section_key_number_ipsec_conf { return $key1; } } - } } 1 diff --git a/lib/network/modem.pm b/lib/network/modem.pm index 29afb69..839b71c 100644 --- a/lib/network/modem.pm +++ b/lib/network/modem.pm @@ -37,12 +37,7 @@ sub ppp_read_conf() { /^METRIC=(.*)/ and $modem->{METRIC} = $1; } $modem->{login} ||= $l{Username}; - my $secret = network::tools::read_secret_backend(); - foreach (@$secret) { - $modem->{passwd} ||= $_->{passwd} if $_->{login} eq $modem->{login}; - } - #my $secret = network::tools::read_secret_backend(); - #my @cnx_list = map { $_->{server} } @$secret; + $modem->{passwd} = network::tools::passwd_by_login($modem->{login}); $modem->{$_} ||= '' foreach qw(connection phone login passwd auth domain dns1 dns2); $modem->{auto_gateway} ||= defined $modem->{Gateway} && $modem->{Gateway} ne '0.0.0.0' ? N("Manual") : N("Automatic"); $modem->{auto_ip} ||= defined $modem->{IPAddr} && $modem->{IPAddr} ne '0.0.0.0' ? N("Manual") : N("Automatic"); @@ -60,7 +55,7 @@ sub ppp_configure { if ($modem->{device} ne "/dev/modem") { my $dev = $modem->{device}; $dev =~ s!^/dev/!!; - any::devfssymlinkf({ device => $dev }, 'modem'); + devices::symlink_now_and_register({ device => $dev }, 'modem'); } my %toreplace = map { $_ => $modem->{$_} } qw(Authentication AutoName connection dns1 dns2 domain IPAddr login passwd phone SubnetMask); diff --git a/lib/network/monitor.pm b/lib/network/monitor.pm index c0ed8f8..7cd1277 100644 --- a/lib/network/monitor.pm +++ b/lib/network/monitor.pm @@ -31,28 +31,41 @@ sub list_wireless { 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{$1}{frequency} ||= $2; + $networks{$ap}{frequency} ||= $frequency; #- signal level is really too high in wpa_supplicant #- this should be standardized at some point - $networks{$1}{signal_level} ||= int($3/3.5); - $networks{$1}{flags} ||= $4; - $networks{$1}{essid} ||= $5 if $5 ne '<hidden>'; + $networks{$ap}{signal_strength} ||= int($signal_strength/3.5); + my $adhoc = $flags =~ s/\[ibss\]//i; + $networks{$ap}{mode} ||= $adhoc ? "Ad-Hoc" : "Managed"; + $networks{$ap}{flags} ||= $flags; + $networks{$ap}{essid} ||= $essid; } #- network id / ssid / bssid / flags while ($list =~ /^(\d+)\t(.*?)\t(.*?)\t(.*)$/mg) { - if (my $net = $networks{$3} || find { $_->{essid} eq $2 } values(%networks)) { + 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]'); } } - } elsif ($o_intf) { + } else { #- else use iwlist - my $current_essid = chomp_(`/sbin/iwgetid -r $o_intf`); - my $current_ap = lc(chomp_(`/sbin/iwgetid -r -a $o_intf`)); - my @list = `/sbin/iwlist $o_intf scanning`; + 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 =~ m!/! ? eval($qual)*100 : $qual; + }; foreach (@list) { if ((/^\s*$/ || /Cell/) && exists $net->{ap}) { $net->{current} = to_bool($net->{essid} && $net->{essid} eq $current_essid || $net->{ap} eq $current_ap); @@ -62,16 +75,23 @@ sub list_wireless { /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]'; + $_ =~ $quality_match and $net->{signal_strength} = $eval_quality->($1); + m|Signal level:([0-9]+/[0-9]+)| && !$net->{signal_strength} and $net->{signal_strength} = eval($1)*100; + /Extra:wpa_ie=|IE:.*WPA/ and $net->{flags} = '[WPA]'; /key:(\S*)\s/ and $net->{flags} ||= $1 eq 'on' && '[WEP]'; } + 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; + } + } } - $networks{$_}{approx_level} = 20 + min(80, int($networks{$_}{signal_level}/20)*20) foreach keys %networks; + foreach (values %networks) { + $_->{essid} eq '<hidden>' and undef $_->{essid}; + $_->{name} = $_->{essid} || "[$_->{ap}]"; + } (\%networks, $has_roaming); } diff --git a/lib/network/ndiswrapper.pm b/lib/network/ndiswrapper.pm index 83f0c37..27df51c 100644 --- a/lib/network/ndiswrapper.pm +++ b/lib/network/ndiswrapper.pm @@ -15,7 +15,7 @@ sub present_devices { my ($driver) = @_; my @supported_devices; foreach (all($::prefix . "$ndiswrapper_root/$driver")) { - my ($ids) = /^([0-9A-Z]{4}:[0-9A-Z]{4})\.[05]\.conf$/; + my ($ids) = /^([0-9A-F]{4}:[0-9A-F]{4})\.[0-9A-F]\.conf$/; $ids and push @supported_devices, $ids; } grep { member(uc(sprintf("%04x:%04x", $_->{vendor}, $_->{id})), @supported_devices) } detect_devices::probeall(); @@ -30,7 +30,7 @@ sub get_devices { sub ask_driver { my ($in) = @_; - if (my $inf_file = $in->ask_file(N("Please select the Windows driver (.inf file)"), "/mnt/cdrom")) { + if (my $inf_file = $in->ask_file(N("Please select the Windows driver (.inf file)"), "/media/cdrom")) { my $driver = basename(lc($inf_file)); $driver =~ s/\.inf$//; @@ -53,13 +53,10 @@ sub find_matching_devices { my $net_path = '/sys/class/net'; my @devices; + require network::connection::ethernet; foreach my $interface (all($net_path)) { - my $dev_path = "$net_path/$interface/device"; - -l $dev_path or next; - my $map = detect_devices::get_sysfs_device_id_map($dev_path); - if (every { hex(chomp_(cat_("$dev_path/" . $map->{$_}))) eq $device->{$_} } keys %$map) { - my $driver = readlink("$dev_path/driver"); - $driver =~ s!.*/!!; + if (network::connection::ethernet::device_matches_interface($device, $interface)) { + my $driver = network::connection::ethernet::interface_to_driver($interface); push @devices, [ $interface, $driver ] if $driver; } } @@ -94,6 +91,10 @@ sub setup_device { if (@conflicts) { $in->ask_yesorno(N("Warning"), N("The selected device has already been configured with the %s driver. Do you really want to use a ndiswrapper driver?", $conflicts[0][1])) or return; + #- unload the old module and try immediately to load ndiswrapper + eval { modules::unload($conflicts[0][1]) }; + eval { modules::unload("ndiswrapper") }; + eval { modules::load("ndiswrapper") }; } my $interface = find_interface($device); @@ -105,4 +106,33 @@ Do you really want to use a ndiswrapper driver?", $conflicts[0][1])) or return; $interface; } +sub select_device { + my ($in) = @_; + my $driver; + my @drivers = installed_drivers(); + if (@drivers) { + $driver ||= first(@drivers); + $in->ask_from('', N("Choose an ndiswrapper driver"), [ + { type => "list", val => \$driver, allow_empty_list => 1, + list => [ undef, @drivers ], + format => sub { defined $_[0] ? N("Use the ndiswrapper driver %s", $_[0]) : N("Install a new driver") } } + ]) or return; + } + $driver ||= ask_driver($in) or return; + + my @devices = get_devices($in, $driver) or return; + my $device; + if (@devices == 1) { + #- only one device matches installed driver + $device = $devices[0]; + } else { + $in->ask_from('', N("Select a device:"), [ + { type => "list", val => \$device, allow_empty_list => 1, + list => [ present_devices($driver) ], + format => sub { $_[0]{description} } } + ]) or return; + } + return $device; +} + 1; diff --git a/lib/network/netconnect.pm b/lib/network/netconnect.pm index adf7f20..ee47c56 100644 --- a/lib/network/netconnect.pm +++ b/lib/network/netconnect.pm @@ -11,22 +11,14 @@ use services; use network::network; use network::tools; use network::thirdparty; +use network::connection; sub detect { my ($modules_conf, $auto_detect, $o_class) = @_; my %l = ( isdn => sub { - require network::isdn; - $auto_detect->{isdn} = network::isdn::detect_backend($modules_conf); - }, - lan => sub { # ethernet - require network::ethernet; - modules::load_category($modules_conf, list_modules::ethernet_categories()); - $auto_detect->{lan} = { map { $_->[0] => $_->[1] } network::ethernet::get_eth_cards($modules_conf) }; - }, - adsl => sub { - require network::adsl; - $auto_detect->{adsl} = network::adsl::adsl_detect(); + require network::connection::isdn; + $auto_detect->{isdn} = network::connection::isdn::detect_backend($modules_conf); }, modem => sub { $auto_detect->{modem} = { map { $_->{description} || "$_->{MANUFACTURER}|$_->{DESCRIPTION} ($_->{device})" => $_ } detect_devices::getModem($modules_conf) }; @@ -59,30 +51,17 @@ sub real_main { my ($net, $in, $modules_conf) = @_; #- network configuration should have been already read in $net at this point my $mouse = $::o->{mouse} || {}; - my ($cnx_type, @all_cards, %eth_intf, %all_eth_intf, %unavailable_wireless_intf); - my (%connections, @connection_list); + my (@connections_list, $connection, @providers_data, $provider_name, $protocol_settings, $access_settings, $control_settings); + my $connection_compat; + my ($hardware_settings, $network_access_settings, $address_settings, $hostname_settings); my ($modem, $modem_name, $modem_dyn_dns, $modem_dyn_ip); - my $cable_no_auth; - my (@adsl_devices, %adsl_cards, %adsl_data, $adsl_data, $adsl_provider, $adsl_old_provider, $adsl_vpi, $adsl_vci); - my ($ntf_name, $gateway_ex, $up); + my ($up); my ($isdn, $isdn_name, $isdn_type, %isdn_cards, @isdn_dial_methods); my $my_isdn = join('', N("Manual choice"), " (", N("Internal ISDN card"), ")"); - my (@ndiswrapper_drivers, $ndiswrapper_driver, $ndiswrapper_device); - my ($is_wireless, $wireless_enc_mode, $wireless_enc_key, $need_rt2x00_iwpriv, $wireless_roaming, $need_wpa_supplicant); - my ($dvb_adapter, $dvb_ad, $dvb_net, $dvb_pid); - my ($module, $auto_ip, $protocol, $onboot, $needhostname, $peerdns, $peeryp, $peerntpd, $ifplugd, $track_network_id, $ipv6_tunnel, $need_network_restart); my $success = 1; - my $ethntf = {}; my $db_path = "/usr/share/apps/kppp/Provider"; my (%countries, @isp, $country, $provider, $old_provider); - my %l10n_lan_protocols = ( - static => N("Manual configuration"), - dhcp => N("Automatic IP (BOOTP/DHCP)"), - if_(0, - dhcp_zeroconf => N("Automatic IP (BOOTP/DHCP/Zeroconf)"), - ) - ); my $_w = N("Protocol for the rest of the world"); my %isdn_protocols = ( 2 => N("European protocol (EDSS1)"), @@ -91,56 +70,6 @@ sub real_main { $net->{autodetect} = {}; - my $lan_detect = sub { - detect($modules_conf, $net->{autodetect}, 'lan'); - @all_cards = network::ethernet::get_eth_cards($modules_conf); - %all_eth_intf = network::ethernet::get_eth_cards_names(@all_cards); #- needed not to loose GATEWAYDEV - %eth_intf = map { $_->[0] => join(': ', $_->[0], $_->[2] || N("Unknown driver")) } - grep { to_bool($is_wireless) == detect_devices::is_wireless_interface($_->[0]) } @all_cards; - my %available; - $available{$_->[2]} = undef foreach grep { $_->[2] } @all_cards; - %unavailable_wireless_intf = map { - $_->{driver} => sprintf('%s (%s): %s', N("unknown"), $_->{driver}, $_->{description}); - } grep { !exists($available{$_->{description}}) } modules::probe_category('network/wireless'); - }; - - my $is_dvb_interface = sub { $_[0]{DEVICE} =~ /^dvb\d+_\d+/ }; - - my $find_lan_module = sub { - if (my $dev = find { $_->{device} eq $ethntf->{DEVICE} } detect_devices::pcmcia_probe()) { # PCMCIA case - $module = $dev->{driver}; - } elsif ($dev = find { $_->[0] eq $ethntf->{DEVICE} } @all_cards) { - $module = $dev->[1]; - } elsif ($is_dvb_interface->($ethntf)) { - $module = $dvb_adapter->{driver}; - } else { $module = "" } - }; - - my %adsl_descriptions = ( - speedtouch => N("Alcatel speedtouch USB modem"), - sagem => N("Sagem USB modem"), - bewan => N("Bewan modem"), - eci => N("ECI Hi-Focus modem"), # this one needs eci agreement - ); - - my %adsl_types = ( - dhcp => N("Dynamic Host Configuration Protocol (DHCP)"), - static => N("Manual TCP/IP configuration"), - pptp => N("Point to Point Tunneling Protocol (PPTP)"), - pppoe => N("PPP over Ethernet (PPPoE)"), - pppoa => N("PPP over ATM (PPPoA)"), - capi => N("DSL over CAPI"), - ); - - my %encapsulations = ( - 1 => N("Bridged Ethernet LLC"), - 2 => N("Bridged Ethernet VC"), - 3 => N("Routed IP LLC"), - 4 => N("Routed IP VC"), - 5 => N("PPPoA LLC"), - 6 => N("PPPoA VC"), - ); - my %ppp_auth_methods = ( 0 => N("Script-based"), 1 => N("PAP"), @@ -149,95 +78,34 @@ sub real_main { 4 => N("PAP/CHAP"), ); - my $offer_to_connect = sub { - #- FIXME: create $try_to_connect sub out of this code - #- merge with "ask_connect_now" post code - if ($net->{type} eq 'adsl' && !member($net->{adsl}{method}, qw(static dhcp)) || - member($net->{type}, qw(modem isdn isdn_external))) { - return "ask_connect_now"; - } - - unless ($::isInstall) { - if ($need_network_restart) { - services::restart("network"); - } else { - #- FIXME: move this in network::tools::restart_net_interface - network::tools::stop_net_interface($net, 0); - if (exists $net->{adsl}{ethernet_device}) { - network::tools::stop_interface($net->{adsl}{ethernet_device}, 0); - network::tools::start_interface($net->{adsl}{ethernet_device}, 0); - } - network::tools::start_net_interface($net, 0); - } - } - #- FIXME: check for connection here - #- check for real interface in connection test - #- don't block when checking connection - #- return "after_connect" (old "disconnect" step) - return "end"; - }; - - my $after_lan_intf_selection = sub { $is_wireless ? 'wireless' : 'lan_protocol' }; - - my $after_start_on_boot_step = sub { - #- can't be done in adsl_account step because of static/dhcp adsl methods - #- we need to write sagem specific parameters and load corresponding modules/programs (sagem/speedtouch) - $net->{type} eq 'adsl' and network::adsl::adsl_conf_backend($in, $modules_conf, $net); - - network::network::configure_network($net, $in, $modules_conf); - #- FIXME: always run "ask_connect_now" - return $offer_to_connect->(); - }; - - my $goto_start_on_boot_ifneeded = sub { - return $after_start_on_boot_step->() if $net->{type} eq "lan"; - return "isdn_dial_on_boot" if $net->{type} eq 'isdn'; - return "network_on_boot"; - }; - - my $delete_gateway_settings = sub { - my ($device) = @_; - #- delete gateway settings if gateway device is invalid or matches the reconfigured device - if (!$net->{network}{GATEWAYDEV} || !exists $eth_intf{$net->{network}{GATEWAYDEV}} || $net->{network}{GATEWAYDEV} eq $device) { - delete $net->{network}{GATEWAY}; - delete $net->{network}{GATEWAYDEV}; - } - }; - - my $ndiswrapper_do_device_selection = sub { - $ntf_name = network::ndiswrapper::setup_device($in, $ndiswrapper_device); - unless ($ntf_name) { - undef $ndiswrapper_device; - return; - } - - #- redetect interfaces (so that the ndiswrapper module can be detected) - $lan_detect->(); - - $ethntf = $net->{ifcfg}{$ntf_name} ||= { DEVICE => $ntf_name }; - - 1; - }; - - my $ndiswrapper_do_driver_selection = sub { - my @devices = network::ndiswrapper::get_devices($in, $ndiswrapper_driver); - - if (!@devices) { - undef $ndiswrapper_driver; - return; - } elsif (@devices == 1) { - #- only one device matches installed driver - $ndiswrapper_device = $devices[0]; - return $ndiswrapper_do_device_selection->(); + my %steps_compat = ( + 'network::connection::isdn' => 'isdn', + 'network::connection::pots' => 'modem', + ); + + my $get_next = sub { + my ($step) = @_; + my @steps = ( + "select_connection" => sub { 0 }, + "configure_hardware" => sub { $connection->can('get_hardware_settings') && !$connection->{device}{no_hardware_settings} }, + #- network is for example wireless/3G access point + "select_network" => sub { $connection->can('get_networks') }, + "configure_network_access" => sub { $connection->can('get_network_access_settings') }, + #- allow to select provider after network + "select_provider" => sub { $connection->can('get_providers') }, + #- protocol may depend on provider settings (xDSL) + "select_protocol" => sub { $connection->can('get_protocols') }, + #- peer settings may depend on provider and protocol (VPI/VCI for xDSL) + "configure_access" => sub { $connection->can('get_access_settings') }, + "configure_address" => sub { $connection->can('get_address_settings') || $connection->can('get_hostname_settings') }, + "configure_control" => sub { $connection->can('get_control_settings') }, + "apply_connection" => sub { 1 }, + ); + my $can; + foreach (group_by2(@steps)) { + $can && $_->[1]->() and return $_->[0]; + $can ||= $_->[0] eq $step; } - - 1; - }; - - my $ndiswrapper_next_step = sub { - return $ndiswrapper_device ? $after_lan_intf_selection->() : - $ndiswrapper_driver ? 'ndiswrapper_select_device' : - 'ndiswrapper_select_driver'; }; use locale; @@ -249,39 +117,199 @@ sub real_main { defaultimage => "drakconnect.png", name => N("Network & Internet Configuration"), pages => { - welcome => - { - pre => sub { - my @connections = ( - [ N("LAN connection"), "lan" ], - [ N("Wireless connection"), "lan" ], - [ N("ADSL connection"), "adsl" ], - [ N("Cable connection"), "cable" ], - [ N("ISDN connection"), "isdn" ], - [ N("Modem connection"), "modem" ], - [ N("DVB connection"), "dvb" ], - ); - - foreach (@connections) { - my ($string, $type) = @$_; - $connections{$string} = $type; - } - @connection_list = { val => \$cnx_type, type => 'list', list => [ map { $_->[0] } @connections ], }; - }, + welcome => { + pre => sub { undef $net->{type} }, if_(!$::isInstall, no_back => 1), name => N("Choose the connection you want to configure"), interactive_help_id => 'configureNetwork', - data => \@connection_list, - post => sub { - $is_wireless = $cnx_type eq N("Wireless connection"); - return $net->{type} = $connections{$cnx_type}; + data => [ { list => [ network::connection::get_types ], + type => 'list', val => \$net->{type}, format => sub { $_[0] && $_[0]->get_type_description }, + gtk => { use_scrolling => 1 } } ], + complete => sub { + my @packages = $net->{type}->can('get_packages') ? $net->{type}->get_packages : (); + if (@packages && !$in->do_pkgs->install(@packages)) { + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); + 1; + } }, + post => sub { + if (exists $steps_compat{$net->{type}}) { + return $steps_compat{$net->{type}}; + } + @connections_list = $net->{type}->get_connections; + @connections_list ? "select_connection" : "no_connection"; + }, + }, + + select_connection => { + name => sub { $net->{type}->get_type_name . "\n\n" . N("Select the network interface to configure:") }, + data => [ { val => \$connection, type => 'list', list => \@connections_list, + format => sub { $_[0] && $_[0]->get_description }, allow_empty_list => 1 } ], + complete => sub { + $connection->setup_thirdparty($in) or return 1; + $connection->prepare_device; + if ($connection->can("check_device") && !$connection->check_device) { + $in->ask_warn('', $connection->{device}{error}); + return 1; + } + return 0; + }, + post => sub { + $connection->load_interface_settings; + $get_next->("select_connection"); + }, + }, + + no_connection => { + name => sub { $net->{type}->get_type_name . "\n\n" . N("No device can be found for this connection type.") }, + end => 1, + }, + + configure_hardware => { + pre => sub { + $hardware_settings = $connection->get_hardware_settings; + $connection->guess_hardware_settings if $connection->can('guess_hardware_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Hardware Configuration") }, + data => sub { $hardware_settings }, + complete => sub { + if ($connection->can('check_hardware')) { + my $_w = $in->wait_message('', N("Configuring device...")); + if (!$connection->check_hardware) { + $in->ask_warn(N("Error"), $connection->{hardware}{error}) if $connection->{hardware}{error}; + return 1; + } + } + }, + post => sub { $get_next->("configure_hardware") }, + }, + + select_provider => { + pre => sub { + @providers_data = $connection->get_providers; + require lang; + my $locale_country = lang::c2name($::o->{locale}{country} || lang::read()->{country}); + $provider_name = find { /^$locale_country/ } sort(keys %{$providers_data[0]}); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Please select your provider:") }, + data => sub { + [ { type => "list", val => \$provider_name, separator => $providers_data[1], + list => [ N("Unlisted - edit manually"), sort(keys %{$providers_data[0]}) ], sort => 0 } ]; + }, + post => sub { + if ($provider ne N("Unlisted - edit manually")) { + $connection->set_provider($providers_data[0]{$provider_name}); + } + $get_next->("select_provider"); + }, + }, + + select_network => { + pre => sub { + my $_w = $in->wait_message('', N("Scanning for networks...")); + $connection->get_networks; + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Please select your network:") }, + data => sub { + [ { type => "list", val => \$connection->{network}, allow_empty_list => 1, + list => [ keys %{$connection->{networks}}, undef ], gtk => { use_scrolling => 1 }, + format => sub { exists $connection->{networks}{$_[0]} ? + $connection->{networks}{$_[0]}{name} : + N("Unlisted - edit manually"); + } } ]; + }, + post => sub { + $get_next->("select_network"); + }, + }, + + configure_network_access => { + pre => sub { + $network_access_settings = $connection->get_network_access_settings; + $connection->guess_network_access_settings if $connection->can('guess_network_access_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . $connection->get_network_access_settings_label }, + data => sub { $network_access_settings }, + post => sub { $get_next->("configure_network_access") }, + }, + + select_protocol => { + pre => sub { + $protocol_settings = $connection->get_protocol_settings; + $connection->guess_protocol($net) if $connection->can('guess_protocol'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Please select your connection protocol. +If you do not know it, keep the preselected protocol.") }, + data => sub { $protocol_settings }, + post => sub { $get_next->("select_protocol") }, + }, + + configure_access => { + pre => sub { + $access_settings = $connection->get_access_settings; + $connection->guess_access_settings if $connection->can('guess_access_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . $connection->get_access_settings_label }, + data => sub { $access_settings }, + post => sub { $get_next->("configure_access") }, + }, + + configure_address => { + pre => sub { + $address_settings = $connection->can('get_address_settings') && $connection->get_address_settings; + $connection->guess_address_settings if $connection->can('guess_address_settings'); + $hostname_settings = $connection->can('get_hostname_settings') && $connection->get_hostname_settings; + $connection->guess_hostname_settings if $connection->can('guess_hostname_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . $connection->get_address_settings_label }, + data => sub { [ @$address_settings, @$hostname_settings ] }, + complete => sub { + if ($connection->can('check_address_settings') && !$connection->check_address_settings($net)) { + $in->ask_warn(N("Error"), $connection->{address}{error}{message}); + my $index = eval { find_index { $_->{val} eq $connection->{address}{error}{field} } @$address_settings }; + return 1, $index; + } + return 0; + }, + post => sub { $get_next->("configure_address") }, + }, + + configure_control => { + pre => sub { + $control_settings = $connection->get_control_settings; + $connection->can('get_network_control_settings') and + push @$control_settings, @{$connection->get_network_control_settings}; + $connection->guess_control_settings if $connection->can('guess_control_settings'); + $connection->guess_network_control_settings if $connection->can('guess_network_control_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Connection control") }, + data => sub { $control_settings }, + post => sub { $get_next->("configure_control") }, + }, + + apply_connection => { + name => N("Do you want to start the connection now?"), + type => "yesorno", + complete => sub { + $connection->can('install_packages') && !$connection->install_packages($in); + }, + post => sub { + my ($answer) = @_; + $connection->unload_connection if $connection->can('unload_connection'); + $connection->write_settings($net, $modules_conf); + $connection->prepare_connection if $connection->can('prepare_connection'); + if ($answer) { + $connection->disconnect; + $connection->connect; + } + "end"; #- handle disconnection in install? + }, }, isdn_account => { pre => sub { - network::isdn::get_info_providers_backend($isdn, $provider); + network::connection::isdn::get_info_providers_backend($isdn, $provider); $isdn->{huptimeout} ||= 180; }, name => N("Connection Configuration") . "\n\n" . N("Please fill or check the field below"), @@ -305,38 +333,10 @@ sub real_main { ]; }, post => sub { - network::isdn::write_config($in, $isdn); + network::connection::isdn::apply_config($in, $isdn); $net->{net_interface} = 'ippp0'; - "allow_user_ctl"; - }, - }, - - cable => - { - pre => sub { - $cable_no_auth = sub { $net->{cable}{bpalogin} eq N("None") }; - }, - name => N("Cable: account options"), - data => sub { - [ - { label => N("Authentication"), type => "list", val => \$net->{cable}{bpalogin}, list => [ N("None"), N("Use BPALogin (needed for Telstra)") ] }, - { label => N("Account Login (user name)"), val => \$net->{cable}{login}, disabled => $cable_no_auth }, - { label => N("Account Password"), val => \$net->{cable}{passwd}, hidden => 1, disabled => $cable_no_auth }, - ]; - }, - complete => sub { - !$cable_no_auth->() && !$in->do_pkgs->ensure_is_installed('bpalogin', '/usr/sbin/bpalogin'); + "isdn_dial_on_boot"; }, - post => sub { - my $use_bpalogin = !$cable_no_auth->(); - $use_bpalogin and substInFile { - s/username\s+.*\n/username $net->{cable}{login}\n/; - s/password\s+.*\n/password $net->{cable}{passwd}\n/; - } "$::prefix/etc/bpalogin.conf"; - services::set_status("bpalogin", $use_bpalogin); - $auto_ip = 1; - return "lan"; - } }, isdn => @@ -366,11 +366,11 @@ sub real_main { $isdn->{description} =~ s/\|/ -- /; } - network::isdn::read_config($isdn); + network::connection::isdn::read_config($isdn); $isdn->{driver} = $isdn_cards{$isdn_name}{driver}; #- do not let config overwrite default driver #- let the user choose hisax or capidrv if both are available - $isdn->{driver} ne "capidrv" && network::isdn::get_capi_card($in, $isdn) and return "isdn_driver"; + $isdn->{driver} ne "capidrv" && network::connection::isdn::get_capi_card($in, $isdn) and return "isdn_driver"; return "isdn_protocol"; }, }, @@ -379,7 +379,7 @@ sub real_main { isdn_ask => { pre => sub { - %isdn_cards = network::isdn::get_cards(); + %isdn_cards = network::connection::isdn::get_cards(); }, name => N("Select a device!"), data => sub { [ { label => N("Net Device"), val => \$isdn_name, type => 'list', separator => '|', list => [ keys %isdn_cards ], allow_empty_list => 1 } ] }, @@ -413,7 +413,7 @@ If you have a PCMCIA card, you have to know the \"irq\" and \"io\" of your card. $e = $in->ask_from_listf(N("ISDN Configuration"), N("Which of the following is your ISDN card?"), sub { $_[0]{description} }, - [ network::isdn::get_cards_by_type($isdn->{card_type}) ]) or goto($isdn->{card_type} =~ /usb|pci/ ? 'isdn_ask_step_1' : 'isdn_ask_step_1b'); + [ network::connection::isdn::get_cards_by_type($isdn->{card_type}) ]) or goto($isdn->{card_type} =~ /usb|pci/ ? 'isdn_ask_step_1' : 'isdn_ask_step_1b'); $e->{$_} and $isdn->{$_} = $e->{$_} foreach qw(driver type mem io io0 io1 irq firmware); }, @@ -460,7 +460,7 @@ If you have a PCMCIA card, you have to know the \"irq\" and \"io\" of your card. name => N("ISDN Configuration") . "\n\n" . N("Select your provider.\nIf it is not listed, choose Unlisted."), data => sub { [ { label => N("Provider:"), type => "list", val => \$provider, separator => '|', - list => [ N("Unlisted - edit manually"), network::isdn::read_providers_backend() ] } ]; + list => [ N("Unlisted - edit manually"), network::connection::isdn::read_providers_backend() ] } ]; }, next => "isdn_account", }, @@ -497,9 +497,11 @@ Take a look at http://www.linmodems.org"), #- some modem configuration programs modify modprobe.conf while we're loaded #- so write it now and reload then $modules_conf->write; - my $ret = network::thirdparty::setup_device($in, 'rtc', $driver, $modem, qw(device)); - $modules_conf->read if $ret; - !$ret; + require network::connection::pots; + my $settings = network::thirdparty::apply_settings($in, 'pots', network::connection::pots::get_thirdparty_settings(), $driver); + $modem->{device} = $settings->{device} if $settings; + $modules_conf->read if $settings; + !$settings; }, post => sub { return 'choose_serial_port' if $modem_name eq N("Manual choice"); @@ -526,7 +528,7 @@ Take a look at http://www.linmodems.org"), interactive_help_id => 'selectSerialPort', data => sub { [ { val => \$modem->{device}, format => \&mouse::serial_port2text, type => "list", - list => [ grep { $_ ne $mouse->{device} } (mouse::serial_ports(), grep { -e $_ } '/dev/modem', '/dev/ttySL0', '/dev/ttyS14',) ] } ]; + list => [ grep { $_ ne $mouse->{device} } (mouse::serial_ports(), glob_("/dev/ttyUSB*"), grep { -e $_ } '/dev/modem', '/dev/ttySL0', '/dev/ttyS14',) ] } ]; }, post => sub { return 'ppp_provider'; @@ -639,669 +641,27 @@ Take a look at http://www.linmodems.org"), post => sub { network::modem::ppp_configure($net, $in, $modem); $net->{net_interface} = 'ppp0'; - "allow_user_ctl"; - }, - }, - - - adsl => - { - pre => sub { - $lan_detect->(); - @adsl_devices = keys %eth_intf; - - detect($modules_conf, $net->{autodetect}, 'adsl'); - %adsl_cards = (); - foreach my $modem_type (keys %{$net->{autodetect}{adsl}}) { - foreach my $modem (@{$net->{autodetect}{adsl}{$modem_type}}) { - my $name = join(': ', $adsl_descriptions{$modem_type}, $modem->{description}); - $adsl_cards{$name} = [ $modem_type, $modem ]; - } - } - push @adsl_devices, keys %adsl_cards; - - detect($modules_conf, $net->{autodetect}, 'isdn'); - if (my @isdn_modems = @{$net->{autodetect}{isdn}}) { - require network::isdn; - %isdn_cards = map { $_->{description} => $_ } grep { $_->{driver} =~ /dsl/i } map { network::isdn::get_capi_card($in, $_) } @isdn_modems; - push @adsl_devices, keys %isdn_cards; - } - }, - name => N("ADSL configuration") . "\n\n" . N("Select the network interface to configure:"), - data => [ { label => N("Net Device"), type => "list", val => \$ntf_name, allow_empty_list => 1, - list => \@adsl_devices, format => sub { $eth_intf{$_[0]} || $_[0] } } ], - complete => sub { - exists $adsl_cards{$ntf_name} && !network::thirdparty::setup_device($in, 'dsl', $adsl_cards{$ntf_name}[0]); - }, - post => sub { - if (exists $adsl_cards{$ntf_name}) { - my $modem; - ($ntf_name, $modem) = @{$adsl_cards{$ntf_name}}; - $net->{adsl}{bus} = $modem->{bus} if $ntf_name eq 'bewan'; - } - if (exists($isdn_cards{$ntf_name})) { - require network::isdn; - $net->{adsl}{capi_card} = $isdn_cards{$ntf_name}; - $net->{adsl}{method} = "capi"; - return 'adsl_account'; - } - return 'adsl_provider'; - }, - }, - - - adsl_provider => - { - pre => sub { - require network::adsl_consts; - %adsl_data = %network::adsl_consts::adsl_data if is_empty_hash_ref(\%adsl_data); - $adsl_old_provider = $adsl_provider; - if (!$adsl_provider) { - require lang; - my $locale_country = lang::c2name($::o->{locale}{country} || lang::read()->{country}); - $adsl_provider = find { /^$locale_country/ } sort(keys %adsl_data); - } - }, - name => N("Please choose your ADSL provider"), - data => sub { - [ { label => N("Provider:"), type => "list", val => \$adsl_provider, separator => '|', - list => [ sort(N("Unlisted - edit manually"), keys %adsl_data) ], sort => 0 } ]; - }, - post => sub { - $net->{adsl}{method} = 'pppoa' if member($ntf_name, qw(bewan speedtouch)); - if ($adsl_provider ne N("Unlisted - edit manually")) { - $adsl_data = $adsl_data{$adsl_provider}; - if ($adsl_provider ne $adsl_old_provider) { - $net->{adsl}{$_} = $adsl_data->{$_} foreach qw(Encapsulation vpi vci provider_id method); - $net->{resolv}{$_} = $adsl_data->{$_} foreach qw(DOMAINNAME2); - } - } - return 'adsl_protocol'; - }, - }, - - - adsl_protocol => - { - pre => sub { - # preselect right protocol for ethernet though connections: - if (!exists $adsl_descriptions{$ntf_name}) { - $ethntf = $net->{ifcfg}{$ntf_name} ||= { DEVICE => $ntf_name }; - $net->{adsl}{method} ||= $ethntf->{BOOTPROTO} || "dhcp"; - #- pppoa shouldn't be selected by default for ethernet devices, fallback on pppoe - $net->{adsl}{method} = "pppoe" if $net->{adsl}{method} eq "pppoa"; - } - }, - name => N("Please choose your DSL connection type. -If you do not know it, keep the preselected type."), - data => [ - { text => N("ADSL connection type:"), val => \$net->{adsl}{method}, type => "list", - list => [ sort { $adsl_types{$a} cmp $adsl_types{$b} } keys %adsl_types ], - format => sub { $adsl_types{$_[0]} }, - }, - ], - post => sub { - my $real_interface = $ntf_name; - $net->{type} = 'adsl'; - # blacklist bogus driver, enable ifplugd support else: - $find_lan_module->(); - $ethntf->{MII_NOT_SUPPORTED} ||= bool2yesno(network::ethernet::is_ifplugd_blacklisted($module)); - if ($ntf_name eq "sagem" && member($net->{adsl}{method}, qw(static dhcp))) { - #- "fctStartAdsl -i" builds ifcfg-ethX from ifcfg-sagem and echoes ethX - #- it auto-detects dhcp/static modes thanks to encapsulation setting - $ethntf = $net->{ifcfg}{sagem} ||= {}; - $ethntf->{DEVICE} = "`/usr/sbin/fctStartAdsl -i`"; - $ethntf->{MII_NOT_SUPPORTED} = "yes"; - } - if ($ntf_name eq "speedtouch" && member($net->{adsl}{method}, qw(static dhcp))) { - #- use ATMARP with the atm0 interface - $real_interface = "atm0"; - $ethntf = $net->{ifcfg}{$real_interface} ||= {}; - $ethntf->{DEVICE} = $real_interface; - $ethntf->{ATM_ADDR} = undef; - $ethntf->{MII_NOT_SUPPORTED} = "yes"; - } - #- delete gateway settings if gateway device is invalid or if reconfiguring the gateway interface - exists $net->{ifcfg}{$real_interface} and $delete_gateway_settings->($real_interface); - # process static/dhcp ethernet devices: - if (exists($net->{ifcfg}{$real_interface}) && member($net->{adsl}{method}, qw(static dhcp))) { - $ethntf->{TYPE} = "ADSL"; - $auto_ip = $net->{adsl}{method} eq 'dhcp'; - return 'lan_intf'; - } - member($net->{adsl}{method}, qw(pppoe pptp)) and $net->{adsl}{ethernet_device} = $ntf_name; - return 'adsl_account'; - }, - }, - - - adsl_account => - { - pre => sub { - network::adsl::adsl_probe_info($net); - $net->{net_interface} = 'ppp0'; - $net->{ifcfg}{ppp0} ||= {}; - ($adsl_vpi, $adsl_vci) = (hex($net->{adsl}{vpi}), hex($net->{adsl}{vci})); - }, - name => N("Connection Configuration") . "\n\n" . - N("Please fill or check the field below"), - data => sub { - [ - if_(0, { label => N("Provider name (ex provider.net)"), val => \$net->{resolv}{DOMAINNAME2} }), - { label => N("First DNS Server (optional)"), val => \$net->{resolv}{dnsServer2} }, - { label => N("Second DNS Server (optional)"), val => \$net->{resolv}{dnsServer3} }, - { label => N("Account Login (user name)"), val => \$net->{adsl}{login} }, - { label => N("Account Password"), val => \$net->{adsl}{passwd}, hidden => 1 }, - if_($net->{adsl}{method} ne "capi", - { label => N("Virtual Path ID (VPI):"), val => \$adsl_vpi, advanced => 1 }, - { label => N("Virtual Circuit ID (VCI):"), val => \$adsl_vci, advanced => 1 } - ), - if_($ntf_name eq "sagem", - { label => N("Encapsulation:"), val => \$net->{adsl}{Encapsulation}, list => [ keys %encapsulations ], - format => sub { $encapsulations{$_[0]} }, advanced => 1, - }, - ), - ]; - }, - post => sub { - #- update ATM_ADDR for ATMARP connections - exists $ethntf->{ATM_ADDR} and $ethntf->{ATM_ADDR} = join('.', $adsl_vpi, $adsl_vci); - #- convert VPI/VCI back to hex - ($net->{adsl}{vpi}, $net->{adsl}{vci}) = map { sprintf("%x", $_) } ($adsl_vpi, $adsl_vci); - - $net->{adsl}{device} = - $net->{adsl}{method} eq 'capi' ? 'capi_modem' : - $net->{adsl}{method} eq 'pptp' ? 'pptp_modem' : - $ntf_name; - # FIXME: duplicate with $after_start_on_boot_step sub - network::adsl::adsl_conf_backend($in, $modules_conf, $net); - "allow_user_ctl"; - }, - }, - - - lan => - { - pre => $lan_detect, - name => N("Select the network interface to configure:"), - data => sub { - [ { label => N("Net Device"), type => "list", val => \$ntf_name, list => [ - (sort keys %eth_intf, if_($is_wireless, keys %unavailable_wireless_intf)), - N_("Manually load a driver"), - if_($is_wireless, N_("Use a Windows driver (with ndiswrapper)")), - ], allow_empty_list => 1, format => sub { - translate($eth_intf{$_[0]} || $unavailable_wireless_intf{$_[0]} || $_[0]) } } ]; - }, - complete => sub { - if (any { $_->[0] eq $ntf_name && !$_->[1] } @all_cards) { - $in->ask_warn(N("Error"), N("Unknown driver")); - return 1; - } - - if ($ntf_name eq "Use a Windows driver (with ndiswrapper)") { - require network::ndiswrapper; - $in->do_pkgs->ensure_is_installed('ndiswrapper', '/usr/sbin/ndiswrapper') or return 1; - undef $ndiswrapper_driver; - undef $ndiswrapper_device; - unless (network::ndiswrapper::installed_drivers()) { - $ndiswrapper_driver = network::ndiswrapper::ask_driver($in) or return 1; - return !$ndiswrapper_do_driver_selection->(); - } - } - if (exists $unavailable_wireless_intf{$ntf_name}) { - my $driver = $ntf_name; - network::thirdparty::setup_device($in, 'wireless', $driver) or return 1; - eval { - modules::unload($driver); - modules::load($driver); - }; - $lan_detect->(); - my $eth_card = find { $_->[1] eq $driver } @all_cards; - unless ($eth_card) { - #- FIXME (#17545) - #- "No matching device found for driver %s." - #- "The driver has probably failed to load because of a missing firmware - #- or because it doesn't support your card revision. - #- Have a look at /var/log/messages to find additional information." - $in->ask_warn(N("Error"), N("No device found")); - return 1; - } - $ntf_name = $eth_card->[0]; - } - 0; - }, - post => sub { - if ($ntf_name eq "Manually load a driver") { - require modules::interactive; - modules::interactive::load_category__prompt($in, $modules_conf, list_modules::ethernet_categories()); - return 'lan'; - } elsif ($ntf_name eq "Use a Windows driver (with ndiswrapper)") { - return $ndiswrapper_next_step->(); - } - $ethntf = $net->{ifcfg}{$ntf_name} ||= { DEVICE => $ntf_name }; - return $after_lan_intf_selection->(); - }, - }, - - - lan_protocol => - { - pre => sub { - $find_lan_module->(); - $ethntf->{METRIC} = network::tools::get_default_metric(network::tools::get_interface_type($ethntf, $module)) - unless defined($ethntf->{METRIC}); - $protocol = $l10n_lan_protocols{defined $auto_ip ? ($auto_ip ? 'dhcp' : 'static') : $ethntf->{BOOTPROTO}} || 0; - }, - name => sub { - my $_msg = N("Zeroconf hostname resolution"); - N("Configuring network device %s (driver %s)", $ethntf->{DEVICE}, $module) . "\n\n" . - N("The following protocols can be used to configure a LAN connection. Please choose the one you want to use"); - }, - data => sub { - [ { val => \$protocol, type => "list", list => [ sort values %l10n_lan_protocols ] } ]; - }, - post => sub { - $auto_ip = $protocol ne $l10n_lan_protocols{static} || 0; - return 'lan_intf'; - }, - }, - - - lan_intf => - { - pre => sub { - require network::ethernet; - $onboot = $ethntf->{ONBOOT} ? $ethntf->{ONBOOT} =~ /yes/ : bool2yesno(!member($ethntf->{DEVICE}, - map { $_->{device} } detect_devices::pcmcia_probe())); - $needhostname = $ethntf->{NEEDHOSTNAME} !~ /no/; - $peerdns = $ethntf->{PEERDNS} !~ /no/; - $peeryp = $ethntf->{PEERYP} =~ /yes/; - $peerntpd = $ethntf->{PEERNTPD} =~ /yes/; - # blacklist bogus driver, enable ifplugd support else: - $ifplugd = !text2bool($ethntf->{MII_NOT_SUPPORTED}) && !network::ethernet::is_ifplugd_blacklisted($module); - $track_network_id = $::isStandalone && $ethntf->{HWADDR} || detect_devices::isLaptop(); - delete $ethntf->{TYPE} if $net->{type} ne 'adsl' || !member($net->{adsl}{method}, qw(static dhcp)); - $ethntf->{DHCP_CLIENT} ||= (find { -x "$::prefix/sbin/$_" } qw(dhclient dhcpcd pump dhcpxd)); - $ipv6_tunnel = text2bool($ethntf->{IPV6TO4INIT}); - }, - name => sub { join('', - N("Configuring network device %s (driver %s)", $ethntf->{DEVICE}, $module), - if_(!$auto_ip, "\n\n" . N("Please enter the IP configuration for this machine. -Each item should be entered as an IP address in dotted-decimal -notation (for example, 1.2.3.4).")), - ) }, - data => sub { - [ $auto_ip ? - ( - { text => N("Assign host name from DHCP address"), val => \$needhostname, type => "bool" }, - { label => N("DHCP host name"), val => \$ethntf->{DHCP_HOSTNAME} }, - ) - : - ( - { label => N("IP address"), val => \$ethntf->{IPADDR}, disabled => sub { $auto_ip } }, - { label => N("Netmask"), val => \$ethntf->{NETMASK}, disabled => sub { $auto_ip } }, - ), - { text => N("Track network card id (useful for laptops)"), val => \$track_network_id, type => "bool" }, - { text => N("Network Hotplugging"), val => \$ifplugd, type => "bool", disabled => sub { $wireless_roaming } }, - if_($net->{type} eq "lan", - { text => N("Start at boot"), val => \$onboot, type => "bool" }, - ), - { label => N("Metric"), val => \$ethntf->{METRIC}, advanced => 1 }, - { text => N("Enable IPv6 to IPv4 tunnel"), val => \$ipv6_tunnel, type => "bool", advanced => 1 }, - if_($auto_ip, - { label => N("DHCP client"), val => \$ethntf->{DHCP_CLIENT}, - list => \@network::ethernet::dhcp_clients, advanced => 1 }, - { label => N("DHCP timeout (in seconds)"), val => \$ethntf->{DHCP_TIMEOUT}, advanced => 1 }, - { text => N("Get DNS servers from DHCP"), val => \$peerdns, type => "bool", advanced => 1 }, - { text => N("Get YP servers from DHCP"), val => \$peeryp, type => "bool", advanced => 1 }, - { text => N("Get NTPD servers from DHCP"), val => \$peerntpd, type => "bool", advanced => 1 }, - ), - ]; - }, - complete => sub { - $ethntf->{BOOTPROTO} = $auto_ip ? "dhcp" : "static"; - return 0 if $auto_ip; - if (!is_ip($ethntf->{IPADDR})) { - $in->ask_warn(N("Error"), N("IP address should be in format 1.2.3.4")); - return 1, 0; - } - if (!is_ip($ethntf->{NETMASK})) { - $in->ask_warn(N("Error"), N("Netmask should be in format 255.255.224.0")); - return 1, 1; - } - if (is_ip_forbidden($ethntf->{IPADDR})) { - $in->ask_warn(N("Error"), N("Warning: IP address %s is usually reserved!", $ethntf->{IPADDR})); - return 1, 0; - } - #- test if IP address is already used (do not test for sagem DSL devices since it may use many ifcfg files) - if ($ntf_name ne "sagem" && find { $_->{DEVICE} ne $ethntf->{DEVICE} && $_->{IPADDR} eq $ethntf->{IPADDR} } values %{$net->{ifcfg}}) { - $in->ask_warn(N("Error"), N("%s already in use\n", $ethntf->{IPADDR})); - return 1, 0; - } - }, - focus_out => sub { - $ethntf->{NETMASK} ||= netmask($ethntf->{IPADDR}) unless $ethntf->{NETMASK}; - }, - post => sub { - $ethntf->{ONBOOT} = bool2yesno($onboot); - $ethntf->{NEEDHOSTNAME} = bool2yesno($needhostname); - $ethntf->{PEERDNS} = bool2yesno($peerdns); - $ethntf->{PEERYP} = bool2yesno($peeryp); - $ethntf->{PEERNTPD} = bool2yesno($peerntpd); - $ethntf->{MII_NOT_SUPPORTED} = bool2yesno(!$ifplugd); - $ethntf->{HWADDR} = $track_network_id or delete $ethntf->{HWADDR}; - #- FIXME: special case for sagem where $ethntf->{DEVICE} is the result of a command - #- we can't always use $ntf_name because of some USB DSL modems - $net->{net_interface} = $ntf_name eq "sagem" ? "sagem" : $ethntf->{DEVICE}; - $need_network_restart = $ipv6_tunnel ^ text2bool($ethntf->{IPV6TO4INIT}); - if ($ipv6_tunnel) { - $net->{network}{NETWORKING_IPV6} = "yes"; - $net->{network}{IPV6_DEFAULTDEV} = "tun6to4"; - } - $ethntf->{IPV6INIT} = bool2yesno($ipv6_tunnel); - $ethntf->{IPV6TO4INIT} = bool2yesno($ipv6_tunnel); - if ($auto_ip) { - #- delete gateway settings if gateway device is invalid or if reconfiguring the gateway interface to dhcp - $delete_gateway_settings->($ntf_name); - } - return "static_hostname"; - }, - }, - - ndiswrapper_select_driver => - { - pre => sub { - @ndiswrapper_drivers = network::ndiswrapper::installed_drivers(); - $ndiswrapper_driver ||= first(@ndiswrapper_drivers); - }, - data => sub { - [ { label => N("Choose an ndiswrapper driver"), type => "list", val => \$ndiswrapper_driver, allow_empty_list => 1, - list => [ undef, @ndiswrapper_drivers ], - format => sub { defined $_[0] ? N("Use the ndiswrapper driver %s", $_[0]) : N("Install a new driver") } } ]; - }, - complete => sub { - $ndiswrapper_driver ||= network::ndiswrapper::ask_driver($in) or return 1; - !$ndiswrapper_do_driver_selection->(); - }, - post => $ndiswrapper_next_step, - }, - - ndiswrapper_select_device => - { - data => sub { - [ { label => N("Select a device:"), type => "list", val => \$ndiswrapper_device, allow_empty_list => 1, - list => [ network::ndiswrapper::present_devices($ndiswrapper_driver) ], - format => sub { $_[0]{description} } } ]; - }, - complete => sub { - !$ndiswrapper_do_device_selection->(); + "configure_control_compat"; }, - post => $ndiswrapper_next_step, }, - wireless => - { - pre => sub { - require network::wireless; - $find_lan_module->(); - $need_rt2x00_iwpriv = network::wireless::is_old_rt2x00($module); - $wireless_roaming = delete $ethntf->{WIRELESS_MODE} eq 'Roaming' && !$need_rt2x00_iwpriv; - $ethntf->{WIRELESS_MODE} ||= "Managed"; - $ethntf->{WIRELESS_ESSID} ||= "any"; - ($wireless_enc_key, my $restricted) = network::wireless::get_wep_key_from_iwconfig($ethntf->{WIRELESS_ENC_KEY}); - $wireless_enc_mode = - $ethntf->{WIRELESS_WPA_DRIVER} || $ethntf->{WIRELESS_IWPRIV} =~ /WPAPSK/ ? 'wpa-psk' : - !$wireless_enc_key ? 'none' : - $restricted ? 'restricted' : - 'open'; - delete $ethntf->{WIRELESS_ENC_KEY}; - delete $ethntf->{WIRELESS_IWPRIV}; - delete $ethntf->{WIRELESS_WPA_DRIVER}; - }, - name => N("Please enter the wireless parameters for this card:"), - data => sub { - [ - { label => N("Operating Mode"), val => \$ethntf->{WIRELESS_MODE}, - list => [ N_("Ad-hoc"), N_("Managed"), N_("Master"), N_("Repeater"), N_("Secondary"), N_("Auto") ], - format => \&translate, - disabled => sub { $wireless_roaming } }, - { label => N("Network name (ESSID)"), val => \$ethntf->{WIRELESS_ESSID} }, - { label => N("Encryption mode"), val => \$wireless_enc_mode, - list => [ keys %network::wireless::wireless_enc_modes ], - sort => 1, - format => sub { translate($network::wireless::wireless_enc_modes{$_[0]}) } }, - { label => N("Encryption key"), val => \$wireless_enc_key, disabled => sub { $wireless_enc_mode eq 'none' } }, - { text => N("Allow access point roaming"), val => \$wireless_roaming, type => "bool", - disabled => sub { network::wireless::is_wpa_supplicant_blacklisted($module) } }, - { label => N("Network ID"), val => \$ethntf->{WIRELESS_NWID}, advanced => 1 }, - { label => N("Operating frequency"), val => \$ethntf->{WIRELESS_FREQ}, advanced => 1 }, - { label => N("Sensitivity threshold"), val => \$ethntf->{WIRELESS_SENS}, advanced => 1 }, - { label => N("Bitrate (in b/s)"), val => \$ethntf->{WIRELESS_RATE}, advanced => 1 }, - { label => N("RTS/CTS"), val => \$ethntf->{WIRELESS_RTS}, advanced => 1, - help => N("RTS/CTS adds a handshake before each packet transmission to make sure that the -channel is clear. This adds overhead, but increase performance in case of hidden -nodes or large number of active nodes. This parameter sets the size of the -smallest packet for which the node sends RTS, a value equal to the maximum -packet size disable the scheme. You may also set this parameter to auto, fixed -or off.") - }, - { label => N("Fragmentation"), val => \$ethntf->{WIRELESS_FRAG}, advanced => 1 }, - { label => N("iwconfig command extra arguments"), val => \$ethntf->{WIRELESS_IWCONFIG}, advanced => 1, - help => N("Here, one can configure some extra wireless parameters such as: -ap, channel, commit, enc, power, retry, sens, txpower (nick is already set as the hostname). - -See iwconfig(8) man page for further information."), - }, - { label => - #-PO: split the "xyz command extra argument" translated string into two lines if it's bigger than the english one - N("iwspy command extra arguments"), val => \$ethntf->{WIRELESS_IWSPY}, advanced => 1, - help => N("iwspy is used to set a list of addresses in a wireless network -interface and to read back quality of link information for each of those. - -This information is the same as the one available in /proc/net/wireless : -quality of the link, signal strength and noise level. - -See iwpspy(8) man page for further information."), - }, - if_(!$need_rt2x00_iwpriv, - { label => N("iwpriv command extra arguments"), val => \$ethntf->{WIRELESS_IWPRIV}, advanced => 1, - help => N("iwpriv enable to set up optionals (private) parameters of a wireless network -interface. - -iwpriv deals with parameters and setting specific to each driver (as opposed to -iwconfig which deals with generic ones). - -In theory, the documentation of each device driver should indicate how to use -those interface specific commands and their effect. - -See iwpriv(8) man page for further information."), - }) - ]; - }, - complete => sub { - if ($ethntf->{WIRELESS_FREQ} && $ethntf->{WIRELESS_FREQ} !~ /[0-9.]*[kGM]/) { - $in->ask_warn(N("Error"), N("Freq should have the suffix k, M or G (for example, \"2.46G\" for 2.46 GHz frequency), or add enough '0' (zeroes).")); - return 1, 6; - } - if ($ethntf->{WIRELESS_RATE} && $ethntf->{WIRELESS_RATE} !~ /[0-9.]*[kGM]/) { - $in->ask_warn(N("Error"), N("Rate should have the suffix k, M or G (for example, \"11M\" for 11M), or add enough '0' (zeroes).")); - return 1, 8; - } - if (network::wireless::wlan_ng_needed($module)) { - $in->do_pkgs->ensure_is_installed('prism2-utils', '/sbin/wlanctl-ng') or return 1; - } - $need_wpa_supplicant = ($wireless_roaming || $wireless_enc_mode eq 'wpa-psk') && !$need_rt2x00_iwpriv; - if ($need_wpa_supplicant) { - $in->do_pkgs->ensure_is_installed('wpa_supplicant', '/usr/sbin/wpa_supplicant') or return 1; - } - !network::thirdparty::setup_device($in, 'wireless', $module); - }, - post => sub { - if ($wireless_roaming) { - $ethntf->{MII_NOT_SUPPORTED} = 'no'; - $ethntf->{WIRELESS_MODE} = 'Roaming'; - } elsif (member($wireless_enc_mode, qw(open restricted))) { - $ethntf->{WIRELESS_ENC_KEY} = network::wireless::convert_wep_key_for_iwconfig($wireless_enc_key, $wireless_enc_mode eq 'restricted'); - } elsif ($need_rt2x00_iwpriv) { - #- use iwpriv for WPA with rt2400/rt2500 drivers, they don't plan to support wpa_supplicant - $ethntf->{WIRELESS_IWPRIV} = $wireless_enc_mode eq 'wpa-psk' && qq(set AuthMode=WPAPSK -set EncrypType=TKIP -set SSID=$ethntf->{WIRELESS_ESSID} -set WPAPSK="$wireless_enc_key" -set TxRate=0); - } - - if ($need_wpa_supplicant) { - $ethntf->{WIRELESS_WPA_DRIVER} = network::wireless::wpa_supplicant_get_driver($module); - network::wireless::wpa_supplicant_add_network($ethntf->{WIRELESS_ESSID}, $wireless_enc_mode, $wireless_enc_key); - } - - if (network::wireless::wlan_ng_needed($module)) { - network::wireless::wlan_ng_configure($ethntf->{WIRELESS_ESSID}, $wireless_enc_key, $ethntf->{DEVICE}, $module); - } - return "lan_protocol"; - }, + configure_control_compat => { + pre => sub { + $connection_compat = $net->{type}->new($connection || {}); + network::connection::guess_control_settings($connection_compat); + $control_settings = network::connection::get_control_settings($connection_compat); + }, + name => sub { N("Connection control") }, + data => sub { $control_settings }, + post => sub { + $net->{ifcfg}{$net->{net_interface}}{USERCTL} = bool2yesno($connection_compat->{control}{userctl}); + $net->{ifcfg}{$net->{net_interface}}{ONBOOT} = bool2yesno($connection_compat->{control}{onboot}); + network::network::configure_network($net, $in, $modules_conf); + "ask_connect_now"; + }, }, - - dvb => - { - name => N("DVB configuration") . "\n\n" . N("Select the network interface to configure:"), - data => [ { label => N("DVB Adapter"), type => "list", val => \$dvb_adapter, allow_empty_list => 1, - list => [ modules::probe_category("multimedia/dvb") ], format => sub { $_[0]{description} } } ], - next => "dvb_adapter", - }, - - - dvb_adapter => - { - pre => sub { - my $previous_ethntf = find { $is_dvb_interface->($_) } values %{$net->{ifcfg}}; - $dvb_ad = $previous_ethntf->{DVB_ADAPTER_ID}; - $dvb_net = $previous_ethntf->{DVB_NETWORK_DEMUX}; - $dvb_pid = $previous_ethntf->{DVB_NETWORK_PID}; - if (my $device = find { sysopen(undef, $_, c::O_RDWR() | c::O_NONBLOCK()) } glob("/dev/dvb/adapter*/net*")) { - ($dvb_ad, $dvb_net) = $device =~ m,/dev/dvb/adapter(\d+)/net(\d+),; - } - }, - name => N("DVB adapter settings"), - data => sub { - [ - { label => N("Adapter card"), val => \$dvb_ad }, - { label => N("Net demux"), val => \$dvb_net }, - { label => N("PID"), val => \$dvb_pid }, - ]; - }, - post => sub { - $ntf_name = 'dvb' . $dvb_ad . '_' . $dvb_net; - $ethntf = $net->{ifcfg}{$ntf_name} ||= {}; - $ethntf->{DEVICE} = $ntf_name; - $ethntf->{DVB_ADAPTER_ID} = qq("$dvb_ad"); - $ethntf->{DVB_NETWORK_DEMUX} = qq("$dvb_net"); - $ethntf->{DVB_NETWORK_PID} = qq("$dvb_pid"); - return "lan_protocol"; - }, - }, - - static_hostname => - { - pre => sub { - if ($ethntf->{IPADDR}) { - $net->{resolv}{dnsServer} ||= dns($ethntf->{IPADDR}); - $gateway_ex = gateway($ethntf->{IPADDR}); - # $net->{network}{GATEWAY} ||= gateway($ethntf->{IPADDR}); - if ($ntf_name eq "sagem") { - my @sagem_ip = split(/\./, $ethntf->{IPADDR}); - $sagem_ip[3] = 254; - $net->{network}{GATEWAY} = join(".", @sagem_ip); - } - } - }, - name => N("Please enter your host name. -Your host name should be a fully-qualified host name, -such as ``mybox.mylab.myco.com''. -You may also enter the IP address of the gateway if you have one.") . - " " . # better looking text (to be merged into texts since some languages (eg: ja) doesn't need it -N("Last but not least you can also type in your DNS server IP addresses."), - data => sub { - [ { label => $auto_ip ? N("Host name (optional)") : N("Host name"), val => \$net->{network}{HOSTNAME} }, - if_(!$auto_ip, - { label => N("DNS server 1"), val => \$net->{resolv}{dnsServer} }, - { label => N("DNS server 2"), val => \$net->{resolv}{dnsServer2} }, - { label => N("DNS server 3"), val => \$net->{resolv}{dnsServer3} }, - { label => N("Search domain"), val => \$net->{resolv}{DOMAINNAME}, - help => N("By default search domain will be set from the fully-qualified host name") }, - { label => N("Gateway (e.g. %s)", $gateway_ex), val => \$net->{network}{GATEWAY} }, - if_(@all_cards > 1, - { label => N("Gateway device"), val => \$net->{network}{GATEWAYDEV}, list => [ N_("None"), sort keys %all_eth_intf ], - format => sub { $all_eth_intf{$_[0]} || translate($_[0]) } }, - ), - ), - ]; - }, - complete => sub { - foreach my $dns (qw(dnsServer dnsServer2 dnsServer3)) { - if ($net->{resolv}{$dns} && !is_ip($net->{resolv}{$dns})) { - $in->ask_warn(N("Error"), N("DNS server address should be in format 1.2.3.4")); - return 1; - } - } - if ($net->{network}{GATEWAY} && !is_ip($net->{network}{GATEWAY})) { - $in->ask_warn(N("Error"), N("Gateway address should be in format 1.2.3.4")); - return 1; - } - }, - post => sub { - $net->{network}{GATEWAYDEV} eq "None" and delete $net->{network}{GATEWAYDEV}; - return "zeroconf"; - } - }, - - - zeroconf => - { - name => N("If desired, enter a Zeroconf hostname. -This is the name your machine will use to advertise any of -its shared resources that are not managed by the network. -It is not necessary on most networks."), - data => [ { label => N("Zeroconf Host name"), val => \$net->{zeroconf}{hostname} } ], - complete => sub { - if ($net->{zeroconf}{hostname} =~ /\./) { - $in->ask_warn(N("Error"), N("Zeroconf host name must not contain a .")); - return 1; - } - }, - next => "allow_user_ctl", - }, - - - allow_user_ctl => - { - name => N("Do you want to allow users to start the connection?"), - type => "yesorno", - default => sub { bool2yesno(text2bool($net->{ifcfg}{$net->{net_interface}}{USERCTL})) }, - post => sub { - my ($res) = @_; - $net->{ifcfg}{$net->{net_interface}}{USERCTL} = bool2yesno($res); - return $goto_start_on_boot_ifneeded->(); - }, - }, - - - network_on_boot => - { - name => N("Do you want to start the connection at boot?"), - type => "yesorno", - default => sub { ($net->{type} eq 'modem' ? 'no' : 'yes') }, - post => sub { - my ($res) = @_; - $net->{ifcfg}{$net->{net_interface}}{ONBOOT} = bool2yesno($res); - return $after_start_on_boot_step->(); - }, - }, - - isdn_dial_on_boot => { pre => sub { @@ -1327,7 +687,7 @@ It is not necessary on most networks."), post => sub { my $method = find { $_->{name} eq $isdn->{dial_method} } @isdn_dial_methods; $net->{ifcfg}{ippp0}{$_} = bool2yesno($method->{$_}) foreach qw(ONBOOT DIAL_ON_IFUP); - return $after_start_on_boot_step->(); + return "configure_control_compat"; }, }, @@ -1343,16 +703,10 @@ It is not necessary on most networks."), # local $::isWizard = 0; my $_w = $in->wait_message('', N("Testing your connection..."), 1); network::tools::stop_net_interface($net, 0); - if (exists $net->{adsl}{ethernet_device}) { - network::tools::stop_interface($net->{adsl}{ethernet_device}, 0); - sleep 1; - network::tools::start_interface($net->{adsl}{ethernet_device}, 0); - } sleep 1; network::tools::start_net_interface($net, 1); my $s = 30; $type =~ /modem/ and $s = 50; - $type =~ /adsl/ and $s = 35; $type =~ /isdn/ and $s = 20; sleep $s; $up = network::tools::connected(); @@ -1398,11 +752,30 @@ Test your connection via net_monitor or mcc. If your connection does not work, y #- keeping the translations in case someone want to restore these texts if_(0, + N("Alcatel speedtouch USB modem"), + N("Sagem USB modem"), + N("Bewan modem"), + N("Bewan modem"), + N("ECI Hi-Focus modem"), # this one needs eci agreement + N("LAN connection"), + N("Wireless connection"), + N("ADSL connection"), + N("Cable connection"), + N("ISDN connection"), + N("Modem connection"), + N("DVB connection"), # keep b/c of translations in case they can be reused somewhere else: N("(detected on port %s)", 'toto'), #-PO: here, "(detected)" string will be appended to eg "ADSL connection" N("(detected %s)", 'toto'), N("(detected)"), N("Network Configuration"), + N("Zeroconf hostname resolution"), + N("If desired, enter a Zeroconf hostname. +This is the name your machine will use to advertise any of +its shared resources that are not managed by the network. +It is not necessary on most networks."), + N("Zeroconf Host name"), + N("Zeroconf host name must not contain a ."), N("Because you are doing a network installation, your network is already configured. Click on Ok to keep your configuration, or cancel to reconfigure your Internet & Network connection. "), @@ -1412,6 +785,18 @@ Click on Ok to keep your configuration, or cancel to reconfigure your Internet & N("Configuration is complete, do you want to apply settings?"), N("You have configured multiple ways to connect to the Internet.\nChoose the one you want to use.\n\n"), N("Internet connection"), + N("Select the network interface to configure:"), + N("Configuring network device %s (driver %s)", '', ''), + N("The following protocols can be used to configure a LAN connection. Please choose the one you want to use."), + N("Please enter your host name. +Your host name should be a fully-qualified host name, +such as ``mybox.mylab.myco.com''. +You may also enter the IP address of the gateway if you have one."), + # better looking text (to be merged into texts since some languages (eg: ja) doesn't need it + N("Last but not least you can also type in your DNS server IP addresses."), + N("DNS server address should be in format 1.2.3.4"), + N("Gateway address should be in format 1.2.3.4"), + N("Gateway device"), ); } @@ -1429,33 +814,20 @@ sub safe_main { } } -sub start_internet { - my ($o) = @_; - #- give a chance for module to be loaded using kernel-BOOT modules... - #- FIXME, this has nothing to do there - $::isStandalone or modules::load_category($o->{modules_conf}, 'network/*'); - network::tools::start_net_interface($o->{net}, 1); -} - -sub stop_internet { - my ($o) = @_; - network::tools::stop_net_interface($o->{net}, 1); -} - 1; =head1 network::netconnect::detect() =head2 example of usage -use lib qw(/usr/lib/libDrakX); -use network::netconnect; -use modules; -use Data::Dumper; + use lib qw(/usr/lib/libDrakX); + use network::netconnect; + use modules; + use Data::Dumper; -my %i; -my $modules_conf = modules::any_conf->read; -network::netconnect::detect($modules_conf, \%i); -print Dumper(\%i),"\n"; + my %i; + my $modules_conf = modules::any_conf->read; + network::netconnect::detect($modules_conf, \%i); + print Dumper(\%i),"\n"; =cut diff --git a/lib/network/network.pm b/lib/network/network.pm index 45c5dc2..ceba576 100644 --- a/lib/network/network.pm +++ b/lib/network/network.pm @@ -14,13 +14,14 @@ use network::tools; use vars qw(@ISA @EXPORT); use log; -my $network_file = "/etc/sysconfig/network"; +our $network_file = "/etc/sysconfig/network"; my $resolv_file = "/etc/resolv.conf"; my $tmdns_file = "/etc/tmdns.conf"; +our $wireless_d = "/etc/sysconfig/network-scripts/wireless.d"; @ISA = qw(Exporter); -@EXPORT = qw(addDefaultRoute dns dnsServers gateway guessHostname is_ip is_ip_forbidden masked_ip netmask resolv sethostname); +@EXPORT = qw(addDefaultRoute dns dnsServers gateway guessHostname is_ip is_ip_forbidden masked_ip netmask resolv); #- $net hash structure #- autodetect @@ -98,8 +99,8 @@ sub read_zeroconf() { sub write_network_conf { my ($net) = @_; - if ($net->{network}{HOSTNAME} && $net->{network}{HOSTNAME} =~ /\.(.+)$/) { - $net->{resolv}{DOMAINNAME} = $1; + if ($net->{network}{HOSTNAME} && $net->{network}{HOSTNAME} =~ /\.(.+\..+)$/) { + $net->{resolv}{DOMAINNAME} ||= $1; } $net->{network}{NETWORKING} = 'yes'; @@ -174,18 +175,20 @@ sub update_broadcast_and_network { my ($intf) = @_; my @ip = split '\.', $intf->{IPADDR}; my @mask = split '\.', $intf->{NETMASK}; + #- FIXME: NETWORK and BROADCAST are deprecated, see sysconfig.txt $intf->{BROADCAST} = join('.', mapn { int($_[0]) | ((~int($_[1])) & 255) } \@ip, \@mask); $intf->{NETWORK} = join('.', mapn { int($_[0]) & $_[1] } \@ip, \@mask); } sub write_interface_settings { my ($intf, $file) = @_; - setVarsInSh($file, $intf, qw(DEVICE BOOTPROTO IPADDR NETMASK NETWORK BROADCAST ONBOOT HWADDR METRIC MII_NOT_SUPPORTED TYPE USERCTL ATM_ADDR ETHTOOL_OPTS VLAN MTU MS_DNS1 MS_DNS2 DOMAIN), + setVarsInSh($file, $intf, qw(DEVICE BOOTPROTO IPADDR NETMASK NETWORK BROADCAST GATEWAY ONBOOT HWADDR METRIC MII_NOT_SUPPORTED TYPE USERCTL ATM_ADDR ETHTOOL_OPTS VLAN MTU DNS1 DNS2 DOMAIN RESOLV_MODS LINK_DETECTION_DELAY), qw(WIRELESS_MODE WIRELESS_ESSID WIRELESS_NWID WIRELESS_FREQ WIRELESS_SENS WIRELESS_RATE WIRELESS_ENC_KEY WIRELESS_RTS WIRELESS_FRAG WIRELESS_IWCONFIG WIRELESS_IWSPY WIRELESS_IWPRIV WIRELESS_WPA_DRIVER), qw(DVB_ADAPTER_ID DVB_NETWORK_DEMUX DVB_NETWORK_PID), qw(IPV6INIT IPV6TO4INIT), - qw(MRU REMIP PEERDNS PPPOPTIONS HARDFLOWCTL DEFABORT RETRYTIMEOUT PAPNAME LINESPEED MODEMPORT DEBUG ESCAPECHARS INITSTRING), + qw(MRU REMIP PPPOPTIONS HARDFLOWCTL DEFABORT RETRYTIMEOUT PAPNAME LINESPEED MODEMPORT DEBUG ESCAPECHARS INITSTRING), qw(DISCONNECTTIMEOUT PERSIST DEFROUTE), + qw(VPN_NAME VPN_TYPE), if_($intf->{BOOTPROTO} eq "dhcp", qw(DHCP_CLIENT DHCP_HOSTNAME NEEDHOSTNAME PEERDNS PEERYP PEERNTPD DHCP_TIMEOUT)), if_($intf->{DEVICE} =~ /^ippp\d+$/, qw(DIAL_ON_IFUP)) ); @@ -194,17 +197,22 @@ sub write_interface_settings { log::explanations("written $intf->{DEVICE} interface configuration in $file"); } +sub get_ifcfg_file { + my ($name) = @_; + "$::prefix/etc/sysconfig/network-scripts/ifcfg-$name"; +} + sub write_interface_conf { my ($net, $name) = @_; - my $file = "$::prefix/etc/sysconfig/network-scripts/ifcfg-$name"; + my $file = get_ifcfg_file($name); #- prefer ifcfg-XXX files unlink("$::prefix/etc/sysconfig/network-scripts/$name"); my $intf = $net->{ifcfg}{$name}; - require network::ethernet; - my (undef, $mac_address) = network::ethernet::get_eth_card_mac_address($intf->{DEVICE}); + require network::connection::ethernet; + my (undef, $mac_address) = network::connection::ethernet::get_eth_card_mac_address($intf->{DEVICE}); $intf->{HWADDR} &&= $mac_address; #- set HWADDR to MAC address if required update_broadcast_and_network($intf); @@ -218,7 +226,7 @@ sub write_interface_conf { sub write_wireless_conf { my ($ssid, $ifcfg) = @_; - my $wireless_file = "$::prefix/etc/sysconfig/network-scripts/wireless.d/$ssid"; + my $wireless_file = $::prefix . $wireless_d . '/' . $ssid; write_interface_settings($ifcfg, $wireless_file); # FIXME: write only DHCP/IP settings here substInFile { $_ = '' if /^DEVICE=/ } $wireless_file; @@ -264,14 +272,19 @@ sub addDefaultRoute { c::addDefaultRoute($net->{network}{GATEWAY}) if $net->{network}{GATEWAY}; } -sub sethostname { - my ($net) = @_; - my $text; - my $hostname = $net->{network}{HOSTNAME}; - syscall_("sethostname", $hostname, length $hostname) ? ($text="set sethostname to $hostname") : ($text="sethostname failed: $!"); - log::explanations($text); +sub write_hostname { + my ($hostname) = @_; + + addVarsInSh($::prefix . $network_file, { HOSTNAME => $hostname }, qw(HOSTNAME)); + + add2hosts("localhost", "127.0.0.1"); + add2hosts($hostname, "127.0.0.1") if $hostname; - run_program::run("/usr/bin/run-parts", "--arg", $hostname, "/etc/sysconfig/network-scripts/hostname.d") unless $::isInstall; + unless ($::isInstall) { + my $rc = syscall_("sethostname", $hostname, length $hostname); + log::explanations($rc ? "set sethostname to $hostname" : "sethostname failed: $!"); + run_program::run("/usr/bin/run-parts", "--arg", $hostname, "/etc/sysconfig/network-scripts/hostname.d"); + } } sub resolv($) { @@ -386,11 +399,16 @@ sub netprofile_delete { log::explanations(qq(Deleting "$profile" profile)); } +sub netprofile_clone { + my ($source_profile, $dest_profile) = @_; + return if !$dest_profile || $dest_profile eq "default" || member($dest_profile, netprofile_list()); + system('/sbin/clone-netprofile', $source_profile, $dest_profile); + log::explanations(qq("Creating "$dest_profile" profile)); +} + sub netprofile_add { my ($net, $profile) = @_; - return if !$profile || $profile eq "default" || member($profile, netprofile_list()); - system('/sbin/clone-netprofile', $net->{PROFILE}, $profile); - log::explanations(qq("Creating "$profile" profile)); + netprofile_clone($net->{PROFILE}, $profile); } sub netprofile_list() { @@ -414,11 +432,13 @@ sub miscellaneous_choose { { text => N("Use HTTP proxy for HTTPS connections"), val => \$use_http_for_https, type => "bool" }, { label => N("HTTPS proxy"), val => \$u->{https_proxy}, disabled => sub { $use_http_for_https } }, { label => N("FTP proxy"), val => \$u->{ftp_proxy} }, + { label => N("No proxy for (comma separated list):"), val => \$u->{no_proxy} }, ], complete => sub { $use_http_for_https and $u->{https_proxy} = $u->{http_proxy}; + $u->{no_proxy} =~ s/\s//g; $u->{http_proxy} =~ m,^($|http://), or $in->ask_warn('', N("Proxy should be http://...")), return 1,0; - $u->{https_proxy} =~ m,^($|http://), or $in->ask_warn('', N("Proxy should be https?://...")), return 1,2; + $u->{https_proxy} =~ m,^($|https?://), or $in->ask_warn('', N("Proxy should be http://... or https://...")), return 1,2; $u->{ftp_proxy} =~ m,^($|ftp://|http://), or $in->ask_warn('', N("URL should begin with 'ftp:' or 'http:'")), return 1,3; 0; } @@ -426,92 +446,155 @@ sub miscellaneous_choose { 1; } -sub proxy_configure { - my ($u) = @_; +sub proxy_configure_shell { + my ($proxy) = @_; my $sh_file = "$::prefix/etc/profile.d/proxy.sh"; - setExportedVarsInSh($sh_file, $u, qw(http_proxy https_proxy ftp_proxy)); + setExportedVarsInSh($sh_file, $proxy, qw(http_proxy https_proxy ftp_proxy no_proxy)); chmod 0755, $sh_file; my $csh_file = "$::prefix/etc/profile.d/proxy.csh"; - setExportedVarsInCsh($csh_file, $u, qw(http_proxy https_proxy ftp_proxy)); + setExportedVarsInCsh($csh_file, $proxy, qw(http_proxy https_proxy ftp_proxy no_proxy)); chmod 0755, $csh_file; +} + +sub proxy_configure_kde { + my ($proxy) = @_; - #- KDE proxy settings my $kde_config_dir = "$::prefix/usr/share/config"; + -d $kde_config_dir or return; + my $kde_config_file = "$kde_config_dir/kioslaverc"; - if (-d $kde_config_dir) { - update_gnomekderc($kde_config_file, - undef, - PersistentProxyConnection => "false" - ); - update_gnomekderc($kde_config_file, - "Proxy Settings", - AuthMode => 0, - ProxyType => $u->{http_proxy} || $u->{https_proxy} || $u->{ftp_proxy} ? 4 : 0, - ftpProxy => "ftp_proxy", - httpProxy => "http_proxy", - httpsProxy => "https_proxy" + update_gnomekderc($kde_config_file, + undef, + PersistentProxyConnection => "false" + ); + update_gnomekderc($kde_config_file, + "Proxy Settings", + AuthMode => 0, + ProxyType => $proxy->{http_proxy} || $proxy->{https_proxy} || $proxy->{ftp_proxy} ? 4 : 0, + ftpProxy => "ftp_proxy", + httpProxy => "http_proxy", + httpsProxy => "https_proxy", + NoProxyFor => "no_proxy", ); +} + +#- (protocol, user, password, host, port) +my $http_proxy_match = qr,^(http)://(?:([^:\@]+)(?::([^:\@]+))?\@)?([^\:]+)(?::(\d+))?$,; +#- (protocol, host, port) +my $https_proxy_match = qr,^(https?)://(?:[^:\@]+(?::[^:\@]+)?\@)?([^\:]+)(?::(\d+))?$,; +#- (protocol, protocol, host, port) +my $ftp_proxy_match = qr,^(http|ftp)://(?:[^:\@]+(?::[^:\@]+)?\@)?([^\:]+)(?::(\d+))?$,; +my %proxy_default_port = ( + http => 80, + https => 443, + ftp => 21, +); + +sub proxy_configure_gnome { + my ($proxy) = @_; + + -d "$::prefix/etc/gconf/2/" or return; + + my $defaults_dir = "/etc/gconf/gconf.xml.local-defaults"; + my $p_defaults_dir = "$::prefix$defaults_dir"; + + my $use_alternate_proxy; + my $gconf_set = sub { + my ($key, $type, $value) = @_; + #- gconftool-2 is available since /etc/gconf/2/ exists + run_program::rooted($::prefix, 'gconftool-2', '>', '/dev/null', "--config-source=xml::$p_defaults_dir", "--direct", "--set", "--type=$type", if_($type eq "list", '--list-type', 'string'), $key, $value); + }; + + #- http proxy + if (my ($protocol, $user, $password, $host, $port) = $proxy->{http_proxy} =~ $http_proxy_match) { + $port ||= $proxy_default_port{$protocol} || $proxy_default_port{http}; + $gconf_set->("/system/http_proxy/use_http_proxy", "bool", 1); + $gconf_set->("/system/http_proxy/host", "string", $host); + $gconf_set->("/system/http_proxy/port", "int", $port); + $gconf_set->("/system/http_proxy/use_authentication", "bool", to_bool($user)); + $user and $gconf_set->("/system/http_proxy/authentication_user", "string", $user); + $password and $gconf_set->("/system/http_proxy/authentication_password", "string", $password); + } else { + $gconf_set->("/system/http_proxy/use_http_proxy", "bool", 0); } - #- Gnome proxy settings - if (-d "$::prefix/etc/gconf/2/") { - my $defaults_dir = "/etc/gconf/gconf.xml.local-defaults"; - my $p_defaults_dir = "$::prefix$defaults_dir"; - my $p_defaults_path = "$::prefix/etc/gconf/2/local-defaults.path"; - -r $p_defaults_path or output_with_perm($p_defaults_path, 0755, qq( -# System local settings -xml:readonly:$defaults_dir -)); - -d $p_defaults_dir or mkdir $p_defaults_dir, 0755; - - my $use_alternate_proxy; - my $gconf_set = sub { - my ($key, $type, $value) = @_; - #- gconftool-2 is available since /etc/gconf/2/ exists - system("gconftool-2", "--config-source=xml::$p_defaults_dir", "--direct", "--set", "--type=$type", $key, $value); - }; - - #- http proxy - if (my ($user, $password, $host, $port) = $u->{http_proxy} =~ m,^http://(?:([^:\@]+)(?::([^:\@]+))?\@)?([^\:]+)(?::(\d+))?$,) { - $port ||= 80; - $gconf_set->("/system/http_proxy/use_http_proxy", "bool", 1); - $gconf_set->("/system/http_proxy/host", "string", $host); - $gconf_set->("/system/http_proxy/port", "int", $port); - $gconf_set->("/system/http_proxy/use_authentication", "bool", to_bool($user)); - $user and $gconf_set->("/system/http_proxy/authentication_user", "string", $user); - $password and $gconf_set->("/system/http_proxy/authentication_password", "string", $password); - } else { - $gconf_set->("/system/http_proxy/use_http_proxy", "bool", 0); - } + #- https proxy + if (my ($protocol, $host, $port) = $proxy->{https_proxy} =~ $https_proxy_match) { + $port ||= $proxy_default_port{$protocol} || $proxy_default_port{https}; + $gconf_set->("/system/proxy/secure_host", "string", $host); + $gconf_set->("/system/proxy/secure_port", "int", $port); + $use_alternate_proxy = 1; + } else { + #- clear the ssl host so that it isn't used if the manual proxy is activated for ftp + $gconf_set->("/system/proxy/secure_host", "string", ""); + } - #- https proxy - if (my ($host, $port) = $u->{https_proxy} =~ m,^https?://(?:[^:\@]+(?::[^:\@]+)?\@)?([^\:]+)(?::(\d+))?$,) { - $port ||= 443; - $gconf_set->("/system/proxy/secure_host", "string", $host); - $gconf_set->("/system/proxy/secure_port", "int", $port); - $use_alternate_proxy = 1; - } else { - #- clear the ssl host so that it isn't used if the manual proxy is activated for ftp - $gconf_set->("/system/proxy/secure_host", "string", ""); - } + #- ftp proxy + if (my ($protocol, $host, $port) = $proxy->{ftp_proxy} =~ $ftp_proxy_match) { + $port ||= $proxy_default_port{$protocol} || $proxy_default_port{ftp}; + $gconf_set->("/system/proxy/ftp_host", "string", $host); + $gconf_set->("/system/proxy/ftp_port", "int", $port); + $use_alternate_proxy = 1; + } else { + #- clear the ftp host so that it isn't used if the manual proxy is activated for ssl + $gconf_set->("/system/proxy/ftp_host", "string", ""); + } - #- ftp proxy - if (my ($host, $port) = $u->{ftp_proxy} =~ m,^(?:http|ftp)://(?:[^:\@]+(?::[^:\@]+)?\@)?([^\:]+)(?::(\d+))?$,) { - $port ||= 21; - $gconf_set->("/system/proxy/ftp_host", "string", $host); - $gconf_set->("/system/proxy/ftp_port", "int", $port); - $use_alternate_proxy = 1; - } else { - #- clear the ftp host so that it isn't used if the manual proxy is activated for ssl - $gconf_set->("/system/proxy/ftp_host", "string", ""); - } + my $ignore_hosts = join(',', uniq(qw(localhost 127.0.0.0/8)), split(',', $proxy->{no_proxy})); + $gconf_set->("/system/http_proxy/ignore_hosts", "list", "[$ignore_hosts]"); + + #- set proxy mode to manual if either https or ftp is used + $gconf_set->("/system/proxy/mode", "string", $use_alternate_proxy ? "manual" : "none"); + + #- make gconf daemons reload their settings + system("killall -s HUP gconfd-2"); +} + +sub proxy_configure_mozilla_firefox { + my ($proxy) = @_; - #- set proxy mode to manual if either https or ftp is used - $gconf_set->("/system/proxy/mode", "string", $use_alternate_proxy ? "manual" : "none"); + my $firefox_config_file = "$::prefix/etc/firefox.cfg"; + -f $firefox_config_file or return; - #- make gconf daemons reload their settings - system("killall -s HUP gconfd-2"); + my %prefs; + foreach (qw(http ssl ftp)) { + undef $prefs{"network.proxy.${_}"}; + undef $prefs{"network.proxy.${_}_port"}; + } + if (my ($protocol, undef, undef, $host, $port) = $proxy->{http_proxy} =~ $http_proxy_match) { + $prefs{"network.proxy.http"} = qq("$host"); + $prefs{"network.proxy.http_port"} = $port || $proxy_default_port{$protocol} || $proxy_default_port{http}; } + if (my ($protocol, $host, $port) = $proxy->{https_proxy} =~ $https_proxy_match) { + $prefs{"network.proxy.ssl"} = qq("$host"); + $prefs{"network.proxy.ssl_port"} = $port || $proxy_default_port{$protocol} || $proxy_default_port{https}; + } + if (my ($protocol, $host, $port) = $proxy->{ftp_proxy} =~ $ftp_proxy_match) { + $prefs{"network.proxy.ftp"} = qq("$host"); + $prefs{"network.proxy.ftp_port"} = $port || $proxy_default_port{$protocol} || $proxy_default_port{ftp}; + } + if ($proxy->{no_proxy}) { + $prefs{"network.proxy.no_proxies_on"} = qq("$proxy->{no_proxy}"); + } + $prefs{"network.proxy.type"} = any { defined $prefs{"network.proxy.${_}_port"} } qw(http ssl ftp); + + substInFile { + while (my ($key, $value) = each(%prefs)) { + if (/^defaultPref\("$key",/) { + $_ = defined $value && qq(defaultPref("$key", $value);\n); + delete $prefs{$key}; + } + } + $_ .= join('', map { if_(defined $prefs{$_}, qq(defaultPref("$_", $prefs{$_});\n)) } sort(keys %prefs)) if eof; + } $firefox_config_file; +} + +sub proxy_configure { + my ($proxy) = @_; + proxy_configure_shell($proxy); + proxy_configure_kde($proxy); + proxy_configure_gnome($proxy); + proxy_configure_mozilla_firefox($proxy); } sub read_net_conf { @@ -530,8 +613,8 @@ sub read_net_conf { } } $net->{wireless} ||= {}; - foreach (all("$::prefix/etc/sysconfig/network-scripts/wireless.d")) { - $net->{wireless}{$_} = { getVarsFromSh("$::prefix/etc/sysconfig/network-scripts/wireless.d/$_") }; + foreach (all($::prefix . $wireless_d)) { + $net->{wireless}{$_} = { getVarsFromSh($::prefix . $wireless_d . '/' . $_) }; } netprofile_read($net); if (my $default_intf = network::tools::get_default_gateway_interface($net)) { @@ -559,9 +642,9 @@ sub easy_dhcp { return if text2bool($net->{network}{NETWORKING}); require modules; - require network::ethernet; + require network::connection::ethernet; modules::load_category($modules_conf, list_modules::ethernet_categories()); - my @all_dev = sort map { $_->[0] } network::ethernet::get_eth_cards($modules_conf); + my @all_dev = sort map { $_->[0] } network::connection::ethernet::get_eth_cards($modules_conf); #- only for a single ethernet network card my @ether_dev = grep { /^eth[0-9]+$/ && `LC_ALL= LANG= $::prefix/sbin/ip -o link show $_ 2>/dev/null` =~ m|\slink/ether\s| } @all_dev; @@ -589,26 +672,27 @@ sub easy_dhcp { 1; } +sub reload_net_applet() { + #- make net_applet reload the configuration + my $pid = chomp_(`pidof -x net_applet`); + $pid and kill 1, $pid; +} + sub configure_network { my ($net, $in, $modules_conf) = @_; if (!$::testing) { - require network::ethernet; - network::ethernet::configure_eth_aliases($modules_conf); + require network::connection::ethernet; + network::connection::ethernet::configure_eth_aliases($modules_conf); write_network_conf($net); write_resolv_conf($net); - if ($::isInstall && ! -e "/etc/resolv.conf") { - #- symlink resolv.conf in install root too so that updates and suppl media can be added - symlink "$::prefix/etc/resolv.conf", "/etc/resolv.conf"; - } + write_hostname($net->{network}{HOSTNAME}) if $net->{network}{HOSTNAME}; foreach (keys %{$net->{ifcfg}}) { write_interface_conf($net, $_); my $ssid = $net->{ifcfg}{$_}{WIRELESS_ESSID} or next; write_wireless_conf($ssid, $net->{ifcfg}{$_}); } - network::ethernet::install_dhcp_client($in, $_->{DHCP_CLIENT}) foreach grep { $_->{BOOTPROTO} eq "dhcp" } values %{$net->{ifcfg}}; - add2hosts("localhost", "127.0.0.1"); - add2hosts($net->{network}{HOSTNAME}, "127.0.0.1") if $net->{network}{HOSTNAME}; + network::connection::ethernet::install_dhcp_client($in, $_->{DHCP_CLIENT}) foreach grep { $_->{BOOTPROTO} eq "dhcp" } values %{$net->{ifcfg}}; write_zeroconf($net, $in); any { $_->{BOOTPROTO} =~ /^(pump|bootp)$/ } values %{$net->{ifcfg}} and $in->do_pkgs->install('pump'); @@ -616,12 +700,9 @@ sub configure_network { require network::shorewall; network::shorewall::update_interfaces_list(); - $net->{network}{HOSTNAME} && !$::isInstall and sethostname($net); } - #- make net_applet reload the configuration - my $pid = chomp_(`pidof -x net_applet`); - $pid and kill 1, $pid; + reload_net_applet(); } 1; diff --git a/lib/network/rfswitch.pm b/lib/network/rfswitch.pm new file mode 100644 index 0000000..4617990 --- /dev/null +++ b/lib/network/rfswitch.pm @@ -0,0 +1,38 @@ +package network::rfswitch; + +use strict; +use MDK::Common; +use detect_devices; + +my $conf_file = "/etc/modprobe.d/rfswitch.conf"; + +my @settings = ( + { + match => sub { + # CL56, with buggy BIOS + detect_devices::dmidecode_category('BIOS')->{Vendor} eq 'COMPAL' && + detect_devices::dmidecode_category('System')->{'Product Name'} eq '<BAD INDEX>'; + }, + module => 'acerhk', + options => 'usedritek=1 autowlan=1 force_series=290', + install => 'echo 1 > /proc/driver/acerhk/wirelessled', + remove => 'echo 0 > /proc/driver/acerhk/wirelessled', + }, +); + +sub configure() { + my $setting = find { $_->{match}->() } @settings; + if ($setting) { + output_p($::prefix . $conf_file, + join("\n", + if_($setting->{options}, "options $setting->{module} $setting->{options}"), + if_($setting->{install}, "install $setting->{module} /sbin/modprobe --first-time --ignore-install $setting->{module} && $setting->{install}"), + if_($setting->{remove}, "remove $setting->{module} $setting->{remove}; /sbin/modprobe -r --ignore-remove $setting->{module}"), + "", + )); + require modules; + modules::set_preload_modules('rfswitch', $setting->{module}); + } +} + +1; diff --git a/lib/network/shorewall.pm b/lib/network/shorewall.pm index 2567b48..ce90d4e 100644 --- a/lib/network/shorewall.pm +++ b/lib/network/shorewall.pm @@ -1,12 +1,13 @@ package network::shorewall; # $Id$ use detect_devices; -use network::ethernet; use network::network; use run_program; use common; use log; +my $shorewall_root = "/etc/shorewall"; + sub check_iptables() { -f "$::prefix/etc/sysconfig/iptables" || $::isStandalone && do { @@ -26,18 +27,12 @@ sub set_config_file { } else { $_ = '' if /^[^#]/; } - } "$::prefix/etc/shorewall/$file"; + } "$::prefix${shorewall_root}/$file"; } sub get_config_file { my ($file) = @_; - map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix/etc/shorewall/$file"); -} - -sub get_ifcfg_interface() { - my $net = {}; - network::network::read_net_conf($net); - network::tools::get_default_gateway_interface($net); + map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix${shorewall_root}/$file"); } sub dev_to_shorewall { @@ -47,53 +42,47 @@ sub dev_to_shorewall { $dev; } -sub get_shorewall_interface() { +sub get_net_zone_interfaces { + my ($net) = @_; #- read shorewall configuration first - foreach (get_config_file('interfaces')) { - $_->[0] eq 'net' and return $_->[1]; - } + my @interfaces = map { $_->[1] } grep { $_->[0] eq 'net' } get_config_file('interfaces'); #- else try to find the best interface available - dev_to_shorewall(get_ifcfg_interface()); -} - -our $ask_shorewall_interface_label = N_("Please enter the name of the interface connected to the internet. - -Examples: - ppp+ for modem or DSL connections, - eth0, or eth1 for cable connection, - ippp+ for a isdn connection. -"); - -sub shorewall_interface_choices { - my ($refval) = @_; - my $modules_conf = modules::any_conf->read; - my @all_cards = network::ethernet::get_eth_cards($modules_conf); - my %net_devices = network::ethernet::get_eth_cards_names(@all_cards); - put_in_hash(\%net_devices, { 'ppp+' => 'ppp+', 'ippp+' => 'ippp+' }); - - [ { label => N("Net Device"), val => $refval, list => [ sort keys %net_devices ], format => sub { $net_devices{$_[0]} || $_[0] }, not_edit => 0 } ]; + @interfaces ? @interfaces : dev_to_shorewall(network::tools::get_default_gateway_interface($net)); } -sub read_default_interfaces { +sub get_zones { my ($conf, $o_in) = @_; - my $interface = get_shorewall_interface(); - $o_in and $o_in->ask_from('', translate($ask_shorewall_interface_label), shorewall_interface_choices(\$interface)); - set_net_interface($conf, $interface); + my $net = {}; + network::network::read_net_conf($net); + #- find all interfaces but alias interfaces + my @all_intf = grep { !/:/ } uniq(keys(%{$net->{ifcfg}}), detect_devices::get_net_interfaces()); + my %net_zone = map { $_ => undef } @all_intf; + $net_zone{$_} = 1 foreach get_net_zone_interfaces($net); + $o_in and $o_in->ask_from('', N("Please select the interfaces that will be protected by the firewall. + +All interfaces directly connected to Internet should be selected, +while interfaces connected to a local network may be unselected. + +Which interfaces should be protected? +"), [ + map { + { text => network::tools::get_interface_description($net, $_), val => \$net_zone{$_}, type => 'bool' }; + } (sort keys %net_zone) ]); + ($conf->{net_zone}, $conf->{loc_zone}) = partition { $net_zone{$_} } keys %net_zone; } -sub set_net_interface { +sub add_interface_to_net_zone { my ($conf, $interface) = @_; - $conf->{net_interface} = $interface; - my $net = {}; - network::network::read_net_conf($net); - my @all_intf = uniq((map { dev_to_shorewall($_) } keys %{$net->{ifcfg}}), detect_devices::getNet()); - #- keep all other interfaces (but alias interfaces) in local zone - $conf->{loc_interface} = [ grep { !/:/ && $_ ne $interface } @all_intf ]; + if (!member($interface, @{$conf->{net_zone}})) { + push @{$conf->{net_zone}}, $interface; + @{$conf->{loc_zone}} = grep { $_ ne $interface } @{$conf->{loc_zone}}; + } } sub read { my ($o_in) = @_; - my @rules = get_config_file('rules'); + #- read old rules file if config is not moved to rules.drakx yet + my @rules = get_config_file(-f "$::prefix${shorewall_root}/rules.drakx" ? 'rules.drakx' : 'rules'); my %conf = (disabled => !glob_("$::prefix/etc/rc3.d/S*shorewall"), ports => join(' ', map { my $e = $_; @@ -103,10 +92,14 @@ sub read { $conf{redirects}{$_->[3]}{$_->[2]} = $_->[4] foreach grep { $_->[0] eq 'REDIRECT' } @rules; if (my ($e) = get_config_file('masq')) { - $conf{masq_subnet} = $e->[1]; + ($conf{masq}{net_interface}, $conf{masq}{subnet}) = @$e; } - read_default_interfaces(\%conf, $o_in); - $conf{net_interface} && \%conf; + + my @policy = get_config_file('policy'); + $conf{log_net_drop} = @policy ? (any { $_->[0] eq 'net' && $_->[1] eq 'all' && $_->[2] eq 'DROP' && $_->[3] } @policy) : 1; + + get_zones(\%conf, $o_in); + $conf{net_zone}[0] && \%conf; } sub ports_by_proto { @@ -119,12 +112,44 @@ sub ports_by_proto { \%ports_by_proto; } +sub upgrade_to_shorewall3() { + #- the 'FW' option has been removed from shorewall.conf as of shorewall 3.0 + my $ipsecfile_ok; + substInFile { + undef $_ if /^\s*FW=/; + if ((/^\s*IPSECFILE=/ || eof) && !$ipsecfile_ok) { + $ipsecfile_ok = 1; + $_ = "IPSECFILE=zones\n"; + } + } "$::prefix${shorewall_root}/shorewall.conf"; +} + sub write { - my ($conf) = @_; - my $default_intf = get_ifcfg_interface(); - my $use_pptp = $default_intf =~ /^ppp/ && cat_("$::prefix/etc/ppp/peers/$default_intf") =~ /pptp/; + my ($conf, $o_in) = @_; + my $use_pptp = any { /^ppp/ && cat_("$::prefix/etc/ppp/peers/$_") =~ /pptp/ } @{$conf->{net_zone}}; my $ports_by_proto = ports_by_proto($conf->{ports}); + my ($include_drakx, $other_rules) = partition { $_ eq "INCLUDE\trules.drakx\n" } grep { !/^#/ } cat_("$::prefix${shorewall_root}/rules"); + #- warn if the config is already in rules.drakx and additionnal rules are configured + if (!is_empty_array_ref($include_drakx) && !is_empty_array_ref($other_rules)) { + my %actions = ( + keep => N("Keep custom rules"), + drop => N("Drop custom rules"), + ); + my $action = 'keep'; + !$o_in || $o_in->ask_from_( + { + messages => N("Your firewall configuration has been manually edited and contains +rules that may conflict with the configuration that has just been set up. +What do you want to do?"), + title => N("Firewall"), + icon => 'banner-security', + }, + [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { $actions{$_[0]} } } ]) or return; + #- reset the rules files if the user has chosen to drop modifications + undef $include_drakx if $action eq 'drop'; + } + my $interface_settings = sub { my ($zone, $interface) = @_; [ $zone, $interface, 'detect', if_(detect_devices::is_bridge_interface($interface), 'routeback') ]; @@ -132,28 +157,34 @@ sub write { set_config_file("zones", [ 'net', 'ipv4' ], - if_($conf->{loc_interface}[0], [ 'loc', 'ipv4' ]), + if_($conf->{loc_zone}[0], [ 'loc', 'ipv4' ]), [ 'fw', 'firewall' ], ); set_config_file('interfaces', - $interface_settings->('net', $conf->{net_interface}), - (map { $interface_settings->('loc', $_) } @{$conf->{loc_interface} || []}), + (map { $interface_settings->('net', $_) } @{$conf->{net_zone}}), + (map { $interface_settings->('loc', $_) } @{$conf->{loc_zone} || []}), ); set_config_file('policy', - if_($conf->{loc_interface}[0], [ 'loc', 'net', 'ACCEPT' ], [ 'loc', 'fw', 'ACCEPT' ], [ 'fw', 'loc', 'ACCEPT' ]), + if_($conf->{loc_zone}[0], [ 'loc', 'net', 'ACCEPT' ], [ 'loc', 'fw', 'ACCEPT' ], [ 'fw', 'loc', 'ACCEPT' ]), [ 'fw', 'net', 'ACCEPT' ], - [ 'net', 'all', 'DROP', 'info' ], + [ 'net', 'all', 'DROP', if_($conf->{log_net_drop}, 'info') ], [ 'all', 'all', 'REJECT', 'info' ], ); - set_config_file('rules', + if (is_empty_array_ref($include_drakx)) { + #- make sure the rules.drakx config is read, erasing user modifications + set_config_file('rules', [ 'INCLUDE', 'rules.drakx' ]); + } + output_with_perm("$::prefix${shorewall_root}/" . 'rules.drakx', 0600, map { join("\t", @$_) . "\n" } ( if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'tcp', '1723' ]), if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'gre' ]), (map_each { [ 'ACCEPT', 'net', 'fw', $::a, join(',', @$::b), '-' ] } %$ports_by_proto), (map { map_each { [ 'REDIRECT', 'loc', $::a, $_, $::b, '-' ] } %{$conf->{redirects}{$_}}; } keys %{$conf->{redirects}}), - ); - set_config_file('masq', if_($conf->{masq_subnet}, [ $conf->{net_interface}, $conf->{masq_subnet} ])); + )); + set_config_file('masq', if_(exists $conf->{masq}, [ $conf->{masq}{net_interface}, $conf->{masq}{subnet} ])); + + upgrade_to_shorewall3(); require services; if ($conf->{disabled}) { @@ -164,7 +195,9 @@ sub write { } } -sub update_interfaces_list() { +sub update_interfaces_list { + my ($o_intf) = @_; + $o_intf && member($o_intf, map { $_->[1] } get_config_file('interfaces')) and return; my $shorewall = network::shorewall::read(); $shorewall && !$shorewall->{disabled} and network::shorewall::write($shorewall); } diff --git a/lib/network/signal_strength.pm b/lib/network/signal_strength.pm new file mode 100644 index 0000000..0fa891d --- /dev/null +++ b/lib/network/signal_strength.pm @@ -0,0 +1,14 @@ +package network::signal_strength; + +use common; +use ugtk2; + +my %pixbufs; + +sub get_strength_icon { + my ($network) = @_; + my $approx = 20 + min(80, int($network->{signal_strength}/20)*20); + return $pixbufs{$approx} ||= ugtk2::gtkcreate_pixbuf('wifi-' . sprintf('%03d', $approx) . '.png'); +} + +1; diff --git a/lib/network/squid.pm b/lib/network/squid.pm index 7ca60d2..0a7dcce 100644 --- a/lib/network/squid.pm +++ b/lib/network/squid.pm @@ -18,7 +18,7 @@ sub write_squid_conf { renamef($squid_conf_file, "$squid_conf_file.old"); output($squid_conf_file, qq( -http_port $squid_conf->{http_port}[0] +http_port $squid_conf->{http_port}[0] transparent hierarchy_stoplist cgi-bin ? acl QUERY urlpath_regex cgi-bin \\? no_cache deny QUERY @@ -58,9 +58,6 @@ http_access allow localhost http_reply_access allow all icp_access allow all visible_hostname $squid_conf->{visible_hostname}[0] -httpd_accel_host virtual -httpd_accel_with_proxy on -httpd_accel_uses_host_header on append_domain .$internal_domain_name err_html_text $squid_conf->{admin_mail}[0] deny_info ERR_CUSTOM_ACCESS_DENIED all diff --git a/lib/network/test.pm b/lib/network/test.pm index ec680b7..36da41d 100644 --- a/lib/network/test.pm +++ b/lib/network/test.pm @@ -95,7 +95,7 @@ sub update_status { my ($o) = @_; if ($o->{kid}) { my $fd = $o->{kid}{fd}; - fcntl($fd, c::F_SETFL(), c::O_NONBLOCK()) or die "can not fcntl F_SETFL: $!"; + common::nonblock($fd); local $| = 1; if (defined(my $output = <$fd>)) { ($o->{address}, $o->{ping}) = $output =~ /^([\d\.]+)\|([\d\.,]+)*$/; @@ -111,48 +111,51 @@ sub update_status { =head2 Test synchronously -#- resolve and get ping to hostname from command line if given, else to www.mandriva.com -use lib qw(/usr/lib/libDrakX); -use network::test; +resolve and get ping to hostname from command line if given, else to www.mandriva.com -my $net_test = network::test->new($ARGV[0]); -$net_test->test_synchronous; + use lib qw(/usr/lib/libDrakX); + use network::test; -my $is_connected = $net_test->is_connected; -my $hostname = $net_test->get_hostname; -my $address = $net_test->get_address; -my $ping = $net_test->get_ping; + my $net_test = network::test->new($ARGV[0]); + $net_test->test_synchronous; -print "connected: $is_connected -host: $hostname -resolved host: $address -ping to host: $ping -"; + my $is_connected = $net_test->is_connected; + my $hostname = $net_test->get_hostname; + my $address = $net_test->get_address; + my $ping = $net_test->get_ping; + + print "connected: $is_connected + host: $hostname + resolved host: $address + ping to host: $ping + "; =head2 Test asynchronously -#- resolve and get ping to hostname from command line if given, else to Mandriva -#- prints a "." every 10 miliseconds during connection test -use lib qw(/usr/lib/libDrakX); -use network::test; - -my $net_test = network::test->new($ARGV[0]); -$net_test->start; - -do { - print ".\n"; - select(undef, undef, undef, 0.01); -} while !$net_test->is_done; - -my $is_connected = $net_test->is_connected; -my $hostname = $net_test->get_hostname; -my $address = $net_test->get_address; -my $ping = $net_test->get_ping; - -print "connected: $is_connected -host: $hostname -resolved host: $address -ping to host: $ping -"; +resolve and get ping to hostname from command line if given, else to Mandriva + +prints a "." every 10 miliseconds during connection test + + use lib qw(/usr/lib/libDrakX); + use network::test; + + my $net_test = network::test->new($ARGV[0]); + $net_test->start; + + do { + print ".\n"; + select(undef, undef, undef, 0.01); + } while !$net_test->is_done; + + my $is_connected = $net_test->is_connected; + my $hostname = $net_test->get_hostname; + my $address = $net_test->get_address; + my $ping = $net_test->get_ping; + + print "connected: $is_connected + host: $hostname + resolved host: $address + ping to host: $ping + "; =cut diff --git a/lib/network/thirdparty.pm b/lib/network/thirdparty.pm index b7b8c1e..2c8acb0 100644 --- a/lib/network/thirdparty.pm +++ b/lib/network/thirdparty.pm @@ -9,6 +9,9 @@ use fs::get; use fs; use log; +#- using bsd_glob() since glob("/DONT_EXIST") return "/DONT_EXIST" instead of () (and we don't want this) +use File::Glob ':glob'; + #- network_settings is an hash of categories (rtc, dsl, wireless, ...) #- each category is an hash of device settings @@ -61,220 +64,10 @@ use log; #- o no_club: #- 1 if the package isn't available on Mandriva club -my $firmware_directory = "/lib/firmware"; - -my %network_settings = ( - rtc => - [ - { - matching => qr/^Hcf:/, - description => 'HCF 56k Modem', - url => 'http://www.linuxant.com/drivers/hcf/', - name => 'hcfpcimodem', - kernel_module => { - test_file => 'hcfpciengine', - }, - tools => - { - test_file => '/usr/sbin/hcfpciconfig', - }, - device => '/dev/ttySHCF0', - post => '/usr/sbin/hcfpciconfig --auto', - restart_service => 'hcfpci', - }, - - { - matching => qr/^Hsf:/, - description => 'HSF 56k Modem', - url => 'http://www.linuxant.com/drivers/hsf/', - name => 'hsfmodem', - kernel_module => { - test_file => 'hsfengine', - }, - tools => - { - test_file => '/usr/sbin/hsfconfig', - }, - device => '/dev/ttySHSF0', - post => '/usr/sbin/hsfconfig --auto', - restart_service => 'hsf', - }, - - { - matching => qr/^LT:/, - description => 'LT WinModem', - url => 'http://www.heby.de/ltmodem/', - name => 'ltmodem', - kernel_module => 1, - tools => - { - test_file => '/etc/devfs/conf.d/ltmodem.conf', - }, - device => '/dev/ttyS14', - links => - [ - 'http://linmodems.technion.ac.il/Ltmodem.html', - 'http://linmodems.technion.ac.il/packages/ltmodem/', - ], - }, - - { - matching => [ list_modules::category2modules('network/slmodem') ], - description => 'Smartlink WinModem', - url => 'http://www.smlink.com/content.aspx?id=135/', - name => 'slmodem', - kernel_module => 1, - tools => - { - test_file => '/usr/sbin/slmodemd', - }, - device => '/dev/ttySL0', - post => sub { - my ($driver) = @_; - addVarsInSh("$::prefix/etc/sysconfig/slmodemd", { SLMODEMD_MODULE => $driver }); - }, - restart_service => "slmodemd", - }, - - { - matching => 'sm56', - description => 'Motorola SM56 WinModem', - url => 'http://www.motorola.com/softmodem/driver.htm#linux', - name => 'sm56', - kernel_module => - { - package => 'sm56', - }, - no_club => 1, - device => '/dev/sm56', - }, - ], - - wireless => - [ - { - matching => 'zd1201', - description => 'ZyDAS ZD1201', - url => 'http://linux-lc100020.sourceforge.net/', - firmware => - { - test_file => 'zd1201*.fw', - }, - }, - - (map { - { - matching => "ipw${_}", - description => "Intel(R) PRO/Wireless ${_}", - url => "http://ipw${_}.sourceforge.net/", - name => "ipw${_}", - firmware => - { - url => "http://ipw${_}.sourceforge.net/firmware.php", - test_file => ($_ == 2100 ? "ipw2100-*.fw" : "ipw-2.3-*.fw"), - }, - }; - } (2100, 2200)), - - { - matching => 'prism54', - description => 'Prism GT / Prism Duette / Prism Indigo Chipsets', - url => 'http://prism54.org/', - name => 'prism54', - firmware => - { - url => 'http://prism54.org/~mcgrof/firmware/', - test_file => "isl38*", - }, - }, - - { - matching => qr/^at76c50/, - description => 'Atmel at76c50x cards', - url => 'http://thekelleys.org.uk/atmel/', - name => 'atmel', - firmware => - { - test_file => 'atmel_at76c50*', - }, - links => 'http://at76c503a.berlios.de/', - }, - - { - matching => 'ath_pci', - description => 'Multiband Atheros Driver for WiFi', - url => 'http://madwifi.sourceforge.net/', - name => 'madwifi', - kernel_module => 1, - tools => { - optionnal => 1, - test_file => '/usr/bin/athstats', - }, - }, - ], - - dsl => - [ - { - matching => 'speedtouch', - description => N_("Alcatel speedtouch USB modem"), - url => "http://www.speedtouch.com/supuser.htm", - name => 'speedtouch', - tools => - { - test_file => '/usr/sbin/modem_run', - }, - firmware => - { - package => 'speedtouch_mgmt', - prefix => '/usr/share/speedtouch', - test_file => 'mgmt*.o', - explanations => N_("Copy the Alcatel microcode as mgmt.o in /usr/share/speedtouch/"), - user_install => \&install_speedtouch_microcode, - }, - links => 'http://linux-usb.sourceforge.net/SpeedTouch/mandrake/index.html', - }, - - { - matching => 'eciadsl', - name => 'eciadsl', - explanations => N_("The ECI Hi-Focus modem cannot be supported due to binary driver distribution problem. - -You can find a driver on http://eciadsl.flashtux.org/"), - no_club => 1, - tools => { - test_file => '/usr/sbin/pppoeci', - }, - }, - - { - matching => 'sagem', - description => 'Eagle chipset (from Analog Devices), e.g. Sagem F@st 800/840/908', - url => 'http://www.eagle-usb.org/', - name => 'eagle-usb', - tools => - { - test_file => '/sbin/eaglectrl', - }, - }, - - { - matching => 'bewan', - description => 'Bewan Adsl (Unicorn)', - url => 'http://www.bewan.com/bewan/users/downloads/', - name => 'unicorn', - kernel_module => { - test_file => 'unicorn_.*_atm', - }, - tools => { - optionnal => 1, - test_file => '/usr/bin/bewan_adsl_status', - }, - }, - ], -); - -sub device_get_package { +our $firmware_directory = "/lib/firmware"; +our @thirdparty_types = qw(kernel_module tools firmware); + +sub device_get_packages { my ($settings, $option, $o_default) = @_; $settings->{$option} or return; my $package; @@ -283,25 +76,26 @@ sub device_get_package { } else { $package = $settings->{$option}; } - $package == 1 ? $o_default || $settings->{name} : $package; + $package == 1 ? $o_default || $settings->{name} : ref $package eq 'ARRAY' ? @$package : $package; } sub device_get_option { - my ($settings, $option) = @_; + my ($settings, $option, $o_default) = @_; $settings->{$option} or return; my $value = $settings->{$option}; - $value == 1 ? $settings->{name} : $value; + $value == 1 ? $o_default || $settings->{name} : $value; } sub find_settings { - my ($category, $driver) = @_; + my ($settings_list, $driver) = @_; find { - my $type = ref $_->{matching}; - $type eq 'Regexp' && $driver =~ $_->{matching} || - $type eq 'CODE' && $_->{matching}->($driver) || - $type eq 'ARRAY' && member($driver, @{$_->{matching}}) || - $driver eq $_->{matching}; - } @{$network_settings{$category}}; + my $match = $_->{matching} || $_->{name}; + my $type = ref $match; + $type eq 'Regexp' && $driver =~ $match || + $type eq 'CODE' && $match->($driver) || + $type eq 'ARRAY' && member($driver, @$match) || + $driver eq $match; + } @$settings_list; } sub device_run_command { @@ -318,37 +112,53 @@ sub device_run_command { sub warn_not_installed { my ($in, @packages) = @_; - $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", @packages)); + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); +} + +sub get_checked_element { + my ($settings, $driver, $option) = @_; + $option eq 'firmware' ? + get_firmware_path($settings) : + $option eq 'kernel_module' ? + $driver : + ref $settings->{$option} eq 'HASH' && $settings->{$option}{test_file}; } sub warn_not_found { - my ($in, $settings, $option, @packages) = @_; + my ($in, $settings, $driver, $option, @packages) = @_; my %opt; - $opt{$_} = $settings->{$option}{$_} || $settings->{$_} foreach qw(url explanations no_club); + $opt{$_} = ref $settings->{$option} eq 'HASH' && $settings->{$option}{$_} || $settings->{$_} foreach qw(url explanations no_club no_package); + my $checked = get_checked_element($settings, $driver, $option); $in->ask_warn(N("Error"), - N("Some packages (%s) are required but aren't available.", @packages) . - (!$opt{no_club} && "\n" . N("These packages can be found in Mandriva Club or in Mandriva commercial releases.")) . - ($option eq 'firmware' && "\n\n" . N("Info: ") . "\n" . N("due to missing %s", get_firmware_path($settings))) . - ($opt{url} && "\n\n" . N("The required files can also be installed from this URL: -%s", $opt{url})) . - ($opt{explanations} && "\n\n" . translate($opt{explanations}))); + join('', + ($opt{no_package} ? + N("Some components (%s) are required but aren't available for %s hardware.", $option, $settings->{name}) : + N("Some packages (%s) are required but aren't available.", join(', ', @packages))), + join("\n\n", + if_(!$opt{no_club} && !$opt{no_package}, N("These packages can be found in Mandriva Club or in Mandriva commercial releases.")), + if_($checked, N("The following component is missing: %s", $checked)), + if_($opt{explanations}, translate($opt{explanations})), + if_($opt{url}, N("The required files can also be installed from this URL: +%s", $opt{url})), + ))); } sub is_file_installed { my ($settings, $option) = @_; - my $file = exists $settings->{$option} && $settings->{$option}{test_file}; + my $file = ref $settings->{$option} eq 'HASH' && $settings->{$option}{test_file}; $file && -e "$::prefix$file"; } sub is_module_installed { my ($settings, $driver) = @_; + require modules; my $module = ref $settings->{kernel_module} eq 'HASH' && $settings->{kernel_module}{test_file} || $driver; - find { m!/$module\.k?o! } cat_("$::prefix/lib/modules/" . c::kernel_version() . '/modules.dep'); + modules::module_is_available($module); } sub get_firmware_path { my ($settings) = @_; - my $wildcard = exists $settings->{firmware} && $settings->{firmware}{test_file} or return; + my $wildcard = ref $settings->{firmware} eq 'HASH' && $settings->{firmware}{test_file} or return; my $path = $settings->{firmware}{prefix} || $firmware_directory; "$::prefix$path/$wildcard"; } @@ -356,7 +166,40 @@ sub get_firmware_path { sub is_firmware_installed { my ($settings) = @_; my $pattern = get_firmware_path($settings) or return; - scalar glob_($pattern); + scalar bsd_glob($pattern, undef); +} + +sub extract_firmware { + my ($settings, $in) = @_; + my $choice; + $in->ask_from('', N("Firmware files are required for this device."), + [ { type => "list", val => \$choice, format => \&translate, + list => [ + if_(exists $settings->{firmware}{extract}{floppy_source}, N_("Use a floppy")), + if_(exists $settings->{firmware}{extract}{windows_source}, N_("Use my Windows partition")), + N_("Select file") + ] } ]) or return; + my ($h, $source); + if ($choice eq N_("Use a floppy")) { + $source = $settings->{firmware}{extract}{floppy_source}; + $h = find_file_on_floppy($in, $source); + } elsif ($choice eq N_("Use my Windows partition")) { + $source = $settings->{firmware}{extract}{windows_source}; + $h = find_file_on_windows_system($in, $source); + } else { + $source = $settings->{firmware}{extract}{default_source}; + $h = { file => $in->ask_file(N("Please select the firmware file (for example: %s)", basename($source)), dirname($source)) }; + } + if (!-e $h->{file}) { + log::explanations("Unable to find firmware file (tried to find $source."); + return; + } + + if ($settings->{firmware}{extract}{name}) { + $in->do_pkgs->ensure_is_installed($settings->{firmware}{extract}{name}, $settings->{firmware}{extract}{test_file}) or return; + } + $settings->{firmware}{extract}{run}->($h->{file}); + 1; } sub find_file_on_windows_system { @@ -367,7 +210,7 @@ sub find_file_on_windows_system { fs::get_info_from_fstab($all_hds); if (my $part = find { $_->{device_windobe} eq 'C' } fs::get::fstab($all_hds)) { foreach (qw(windows/system winnt/system windows/system32/drivers winnt/system32/drivers)) { - -d $_ and $source = first(glob_("$part->{mntpoint}/$_/$file")) and last; + -d $_ and $source = first(bsd_glob("$part->{mntpoint}/$_/$file", undef)) and last; } $source or $in->ask_warn(N("Error"), N("Unable to find \"%s\" on your Windows system!", $file)); } else { @@ -379,14 +222,14 @@ sub find_file_on_windows_system { sub find_file_on_floppy { my ($in, $file) = @_; my $floppy = detect_devices::floppy(); - my $mountpoint = '/mnt/floppy'; + my $mountpoint = '/media/floppy'; my $h; $in->ask_okcancel(N("Insert floppy"), N("Insert a FAT formatted floppy in drive %s with %s in root directory and press %s", $floppy, $file, N("Next"))) or return; if (eval { fs::mount::mount(devices::make($floppy), $mountpoint, 'vfat', 'readonly'); 1 }) { log::explanations("Mounting floppy device $floppy in $mountpoint"); $h = before_leaving { fs::mount::umount($mountpoint) }; - if ($h->{file} = first(glob("$mountpoint/$file"))) { + if ($h->{file} = first(bsd_glob("$mountpoint/$file", undef))) { log::explanations("Found $h->{file} on floppy device"); } else { log::explanations("Unabled to find $file on floppy device"); @@ -398,84 +241,75 @@ sub find_file_on_floppy { $h; } -sub install_speedtouch_microcode { - my ($in) = @_; - my $choice; - $in->ask_from('', - N("You need the Alcatel microcode. -You can provide it now via a floppy or your windows partition, -or skip and do it later."), - [ { type => "list", val => \$choice, format => \&translate, - list => [ N_("Use a floppy"), N_("Use my Windows partition") ] } ]) or return; - my ($h, $source); - if ($choice eq N_("Use a floppy")) { - $source = 'mgmt*.o'; - $h = find_file_on_floppy($in, $source); +sub get_required_packages { + my ($type, $settings) = @_; + device_get_packages($settings, $type, if_($type eq 'firmware', "$settings->{name}-firmware")); +} + +sub check_installed { + my ($type, $settings, $driver) = @_; + $type eq 'kernel_module' ? + is_module_installed($settings, $driver) : + $type eq 'firmware' ? + is_firmware_installed($settings) : + is_file_installed($settings, $type); +} + +sub get_available_packages { + my ($type, $in, @names) = @_; + if ($type eq 'kernel_module') { + return map { my $l = $in->do_pkgs->check_kernel_module_packages($_); $l ? @$l : () } @names; } else { - $source = 'alcaudsl.sys'; - $h = find_file_on_windows_system($in, $source); + return $in->do_pkgs->is_available(@names); } - unless (-e $h->{file} && cp_f($h->{file}, "$::prefix/usr/share/speedtouch/mgmt.o")) { - $in->ask_warn(N("Error"), N("Firmware copy failed, file %s not found", $source)); - log::explanations("Firmware copy of $source ($h->{file}) failed"); - return; +} + +sub user_install { + my ($type, $settings, $in) = @_; + if ($type eq 'firmware') { + ref $settings->{$type} eq 'HASH' or return; + if ($settings->{$type}{extract}) { + extract_firmware($settings, $in); + } else { + my $f = $settings->{$type}{user_install}; + $f && $f->($settings, $in); + } + } else { + my $f = ref $settings->{$type} eq 'HASH' && $settings->{$type}{user_install}; + $f && $f->($settings, $in); } - log::explanations("Firmware copy of $h->{file} succeeded"); - $in->ask_warn(N("Congratulations!"), N("Firmware copy succeeded")); - 1; } sub install_packages { my ($in, $settings, $driver, @options) = @_; foreach my $option (@options) { - my %methods = - ( - default => - { - find_package_name => sub { device_get_package($settings, $option) }, - check_installed => sub { is_file_installed($settings, $option) }, - get_packages => sub { my ($name) = @_; $in->do_pkgs->is_available($name) }, - user_install => sub { my $f = $settings->{$option}{user_install}; $f && $f->($in) }, - }, - kernel_module => - { - find_package_name => sub { device_get_package($settings, $option, "$settings->{name}-kernel") }, - check_installed => sub { is_module_installed($settings, $driver) }, - get_packages => sub { my ($name) = @_; my $l = $in->do_pkgs->check_kernel_module_packages($name); $l ? @$l : () } - }, - firmware => - { - find_package_name => sub { device_get_package($settings, $option, "$settings->{name}-firmware") }, - check_installed => sub { is_firmware_installed($settings) }, - }, - ); - my $get_method = sub { my ($method) = @_; exists $methods{$option} && $methods{$option}{$method} || $methods{default}{$method} }; - - my $name = $get_method->('find_package_name')->(); - unless ($name) { + my @packages = get_required_packages($option, $settings); + unless (@packages) { log::explanations(qq(No $option package for module "$driver" is required, skipping)); next; } - if ($get_method->('check_installed')->()) { + if (check_installed($option, $settings, $driver)) { + $settings->{old_status}{$option} = 1; log::explanations(qq(Required $option package for module "$driver" is already installed, skipping)); next; } - if (my @packages = $get_method->('get_packages')->($name)) { - log::explanations("Installing thirdparty packages ($option) " . join(', ', @packages)); - if (!$in->do_pkgs->install(@packages)) { - next if ref $settings->{$option} eq 'HASH' && $settings->{$option}{optionnal}; - warn_not_installed($in, @packages); - } elsif ($get_method->('check_installed')->()) { - next; + my $optional = ref $settings->{$option} eq 'HASH' && $settings->{$option}{optional}; + if (my @avalaible = get_available_packages($option, $in, @packages)) { + log::explanations("Installing thirdparty packages ($option) " . join(', ', @avalaible)); + if ($in->do_pkgs->install(@avalaible) && check_installed($option, $settings, $in)) { + next; + } elsif (!$optional) { + warn_not_installed($in, @avalaible); } } - log::explanations("Thirdparty package $name ($option) is required but not available"); + next if $optional; + log::explanations("Thirdparty package @packages ($option) is required but not available"); - unless ($get_method->('user_install')->($in)) { - warn_not_found($in, $settings, $option, $name); + unless (user_install($option, $settings, $in)) { + warn_not_found($in, $settings, $driver, $option, @packages); return; } } @@ -483,16 +317,22 @@ sub install_packages { 1; } -sub setup_device { - my ($in, $category, $driver, $o_config, @o_fields) = @_; +sub apply_settings { + my ($in, $category, $settings_list, $driver) = @_; - my $settings = find_settings($category, $driver); + my $settings = find_settings($settings_list, $driver); if ($settings) { log::explanations(qq(Found settings for driver "$driver" in category "$category")); my $wait = $in->wait_message('', N("Looking for required software and drivers...")); - install_packages($in, $settings, $driver, qw(kernel_module firmware tools)) or return; + install_packages($in, $settings, $driver, @thirdparty_types) or return; + + if (exists $settings->{firmware} && !$settings->{old_status}{firmware}) { + log::explanations("Reloading module $driver"); + eval { modules::unload($driver) }; + eval { modules::load($driver) }; + } undef $wait; $wait = $in->wait_message('', N("Please wait, running device configuration commands...")); @@ -503,15 +343,14 @@ sub setup_device { services::restart_or_start($service); } + $settings->{sleep} and sleep $settings->{sleep}; + log::explanations(qq(Settings for driver "$driver" applied)); } else { log::explanations(qq(No settings found for driver "$driver" in category "$category")); } - #- assign requested settings, erase with undef if no settings have been found - $o_config->{$_} = $settings->{$_} foreach @o_fields; - - 1; + $settings || {}; } 1; diff --git a/lib/network/tools.pm b/lib/network/tools.pm index 4607979..a65fd7c 100644 --- a/lib/network/tools.pm +++ b/lib/network/tools.pm @@ -7,53 +7,15 @@ use c; use Socket; sub write_secret_backend { - my ($a, $b) = @_; - foreach my $i ("$::prefix/etc/ppp/pap-secrets", "$::prefix/etc/ppp/chap-secrets") { - substInFile { s/^'$a'.*\n//; $_ .= "\n'$a' * '$b' * \n" if eof } $i; - #- restore access right to secrets file, just in case. - chmod 0600, $i; - } -} - -sub unquotify { - my ($word) = @_; - $$word =~ s/^(['"]?)(.*)\1$/$2/; -} - -sub read_secret_backend() { - my $conf = []; - foreach my $i ("pap-secrets", "chap-secrets") { - foreach (cat_("$::prefix/etc/ppp/$i")) { - my ($login, $server, $passwd) = split(' '); - if ($login && $passwd) { - unquotify \$passwd; - unquotify \$login; - unquotify \$server; - push @$conf, {login => $login, - passwd => $passwd, - server => $server }; - } - } - } - $conf; + my ($login, $password) = @_; + require network::connection::ppp; + network::connection::ppp::write_secrets({ access => { login => $login, password => $password } }); } sub passwd_by_login { my ($login) = @_; - - unquotify \$login; - my $secret = read_secret_backend(); - foreach (@$secret) { - return $_->{passwd} if $_->{login} eq $login; - } -} - -sub wrap_command_for_root { - my ($name, @args) = @_; - #- FIXME: duplicate code from common::require_root_capability - check_for_xserver() && fuzzy_pidofs(qr/\bkwin\b/) > 0 ? - ("kdesu", "--ignorebutton", "-c", "$name @args") : - ([ 'consolehelper', $name ], @args); + require network::connection::ppp; + network::connection::ppp::get_secret(undef, $login); } sub run_interface_command { @@ -61,7 +23,7 @@ sub run_interface_command { my @command = !$> || system("/usr/sbin/usernetctl $intf report") == 0 ? ($command, $intf, if_(!$::isInstall, "daemon")) : - wrap_command_for_root($command, $intf); + common::wrap_command_for_root($command, $intf); run_program::raw({ detach => $detach, root => $::prefix }, @command); } @@ -93,7 +55,7 @@ sub connected_bg__raw { local $| = 1; if (ref($kid_pipe) && ref($$kid_pipe)) { my $fd = $$kid_pipe->{fd}; - fcntl($fd, c::F_SETFL(), c::O_NONBLOCK()) or die "can not fcntl F_SETFL: $!"; + common::nonblock($fd); my $a = <$fd>; $$status = $a if defined $a; } else { $$kid_pipe = check_link_beat() } @@ -177,7 +139,9 @@ sub find_matching_interface { #- returns the current gateway, with lowest metric sub get_current_gateway_interface() { my $routes = get_routes(); - first(sort { $routes->{$a}{metric} <=> $routes->{$b}{metric} } grep { exists $routes->{$_}{gateway} } keys %$routes); + first(sort { $routes->{$a}{metric} <=> $routes->{$b}{metric} } grep { + $routes->{$_}{network} eq '0.0.0.0' && $routes->{$_}{gateway}; + } keys %$routes); } #- returns gateway interface if found @@ -197,7 +161,7 @@ sub get_default_gateway_interface { sub get_interface_status { my ($intf) = @_; my $routes = get_routes(); - return $routes->{$intf}{network}, $routes->{$intf}{gateway}; + return $routes->{$intf}{network}, $routes->{$intf}{network} eq '0.0.0.0' && $routes->{$intf}{gateway}; } #- returns (gateway_interface, interface is up, gateway address, dns server address) @@ -219,6 +183,18 @@ sub get_interface_type { "unknown"; } +sub get_interface_description { + my ($net, $interface_name) = @_; + my $type = get_interface_type($net->{ifcfg}{$interface_name}); + #- FIXME: find interface description (from PCI/USB data) and translate + $type eq 'adsl' ? "DSL: $interface_name" : + $type eq 'isdn' ? "ISDN: $interface_name" : + $type eq 'modem' ? "Modem: $interface_name" : + $type eq 'wifi' ? "WiFi: $interface_name" : + member($type, qw(ethernet_gigabit ethernet)) ? "Ethernet: $interface_name" : + $interface_name; +} + sub get_default_metric { my ($type) = @_; my @known_types = ("ethernet_gigabit", "ethernet", "adsl", "wifi", "isdn", "modem", "unknown"); @@ -243,9 +219,9 @@ sub get_routes() { my %routes; foreach (cat_("/proc/net/route")) { if (/^(\S+)\s+([0-9A-F]+)\s+([0-9A-F]+)\s+[0-9A-F]+\s+\d+\s+\d+\s+(\d+)\s+([0-9A-F]+)/) { - if (hex($2)) { $routes{$1}{network} = host_hex_to_dotted($2) } - elsif (hex($3)) { $routes{$1}{gateway} = host_hex_to_dotted($3) } - if ($4) { $routes{$1}{metric} = $4 } + if (defined $3) { $routes{$1}{gateway} = hex($3) ? host_hex_to_dotted($3) : $routes{$1}{network} } + if (defined $2) { $routes{$1}{network} = host_hex_to_dotted($2) } + if (defined $4) { $routes{$1}{metric} = $4 } } } #- TODO: handle IPv6 with /proc/net/ipv6_route diff --git a/lib/network/vpn.pm b/lib/network/vpn.pm new file mode 100644 index 0000000..4a5afbc --- /dev/null +++ b/lib/network/vpn.pm @@ -0,0 +1,191 @@ +package network::vpn; + +=head1 NAME + +network::vpn - VPN connection abstract class + +=cut + +use strict; +use common; + +my $vpn_d = "/etc/sysconfig/network-scripts/vpn.d"; + +=head1 CLASS METHODS + +=head2 Generic class methods + +=over + +=item list_types + +List supported VPN types + +=cut + +sub list_types { + common::load_modules_from_base(__PACKAGE__); +} + +=item get_configured_connections + +Return list of configured connections for this class + +=cut + +sub get_configured_connections { + my ($class) = @_; + map { if_(/^(.*).conf$/, $class->new($1)) } all($::prefix . $vpn_d . '/' . $class->get_type); +} + +=item new(NAME) + +Create a new VPN connection object named NAME + +=cut + +sub new { + my ($class, $name) = @_; + bless { + name => $name, + }, $class; +} + +=back + +=head2 Pure virtual class methods + +=over + +=item get_type + +Return VPN type (preferably one lowercase word) + +=item get_description + +Return description of the VPN type + +=item get_packages + +List package required for configuration + +=back + +=head1 INSTANCE METHODS + +=head2 Generic instance methods + +=over + +=item get_name + +Return name of the VPN connection + +=cut + +sub get_name { + my ($connection) = @_; + $connection->{name}; +} + +=item get_label + +Return label of the VPN connection + +=cut + +sub get_label { + my ($connection) = @_; + sprintf("%s (%s)", $connection->get_name, $connection->get_type); +} + +=item get_config_path + +Get configuration file path + +=cut + +sub get_config_path { + my ($connection) = @_; + $::prefix . $vpn_d . '/' . $connection->get_type . '/' . $connection->get_name . '.conf'; +} + +sub _run { + my ($connection, $action, @args) = @_; + my @command = ('vpn-' . $action, $connection->get_type, $connection->get_name, @args); + @command = common::wrap_command_for_root(@command) if $>; + require run_program; + run_program::rooted($::prefix, , @command); +} + +=item start($o_in) + +Start the VPN connection + +$o_in is an interactive object used to interact with the user, +used if some interactive username/passwords are required. +If not specified, there is no user interaction. + +=cut + +sub start { + my ($connection, $_o_in) = @_; + $connection->_run('start'); +} + +=item stop + +Stop the VPN connection + +=cut + +sub stop { + my ($connection) = @_; + $connection->_run('stop'); +} + +=item is_started + +Returns true if the VPN connection is started + +=cut + +sub is_started { + my ($connection) = @_; + my $pid = chomp_(cat_($::prefix . '/var/run/' . $connection->get_type . '-' . $connection->get_name . '.pid')); + $pid && -e '/proc/' . $pid; +} + +=back + +=head2 Pure virtual instance methods + +=over + +=item read_config + +Read configuration from the file returned by get_config_path() + +=item write_config + +Write configuration to the file returned by get_config_path() + +=item get_settings + +Return an array ref of interactive settings + +=back + +=head2 Optional instance methods + +=over + +=item prepare + +Run commands or services that are required for the VPN type + +=back + +=cut + +1; diff --git a/lib/network/vpn/openvpn.pm b/lib/network/vpn/openvpn.pm new file mode 100644 index 0000000..ac5acf1 --- /dev/null +++ b/lib/network/vpn/openvpn.pm @@ -0,0 +1,407 @@ +package network::vpn::openvpn; + +use base qw(network::vpn); + +use strict; +use common; + +sub get_type { 'openvpn' } +sub get_description { "OpenVPN" } +sub get_packages { 'openvpn', if_(supports_pkcs11(), qw(openct opensc pcsc-lite)) } + +my $pkcs11_tokens; + +sub prepare { + require services; + if (supports_pkcs11()) { + #- don't fail if SmartCard daemons can't start, it's not mandatory + services::start_not_running_service($_) foreach qw(openct pcscd); + cache_pkcs11_tokens(); + } + 1; +} + +sub read_config { + my ($connection) = @_; + my ($pkcs11_slot, $pkcs11_id); + foreach (cat_($connection->get_config_path)) { + /^\s*proto\s+tcp/ and $connection->{tcp} = 1; + /^\s*dev\s+([[:alpha:]]+)(\d*)/ and ($connection->{dev_type}, $connection->{dev_number}) = ($1, $2); + if (/^\s*remote\s+(\S+)(?:\s+(\w+))?/) { + $connection->{gateway} = $1; + $connection->{port} = $2; + } + if (/^\s*tls-auth\s+(\S+)(?:\s+(\d+))?/) { + $connection->{'tls-auth'} = $1; + $connection->{key_direction} = $2; + } + foreach my $type (qw(ca cert key pkcs12 secret)) { + /^\s*$type\s+(.+)/ and $connection->{$type . '_file'} = $1; + } + /^\s*pkcs11-slot\s+(.+)/ and $pkcs11_slot = $1; + /^\s*pkcs11-id\s+(.+)/ and $pkcs11_id = $1; + /^\s*ns-cert-type\s+server/ and $connection->{check_server} = 1; + /^\s*auth-user-pass/ and $connection->{'auth-user-pass'} = 1; + if (/^\s*ifconfig\s+(\S+)\s+(\S+)/) { + $connection->{local_ip} = $1; + $connection->{remote_ip} = $2; + $connection->{addressing} = 'manual'; + } + /^\s*cipher\s+(.+)/ and $connection->{cipher} = $1; + /^\s*keysize\s+(.+)/ and $connection->{keysize} = $1; + } + if (exists $connection->{secret_file}) { + $connection->{type} = 'static'; + $connection->{key} = delete $connection->{secret_file}; + } else { + $connection->{type} = 'pki'; + $connection->{key} = delete $connection->{key_file}; + } + if (defined $pkcs11_slot && defined $pkcs11_id) { + my $tokens = $connection->get_pkcs11_tokens('no_cache'); + $connection->{pkcs11_object} = find { $_->{slot} eq $pkcs11_slot && $_->{id} eq $pkcs11_id } @{$tokens->{objects}}; + $connection->{pkcs11_object} ||= {}; + } +} + +sub write_config { + my ($connection) = @_; + my $file = $connection->get_config_path; + unless (-e $file) { + mkdir_p(dirname($file)); + cp_f("/usr/share/openvpn/sample-config-files/client.conf", $file); + } + + delete $connection->{keysize} if !$connection->{cipher}; + if ($connection->{type} eq 'static') { + $connection->{secret_file} = delete $connection->{key}; + delete $connection->{ca_file}; + delete $connection->{cert_file}; + delete $connection->{key_file}; + } else { + $connection->{key_file} = delete $connection->{key}; + delete $connection->{secret_file}; + } + + my @config = $connection->build_config; + substInFile { + foreach my $conf (@config) { + if (/^;?$conf->{key}\b/) { + if ($conf->{comment}) { + $_ = ";$_" unless /^;/; + } else { + $_ = "$conf->{key} $conf->{value}\n"; + $conf->{comment} = 1; + } + last; + } + } + $_ .= join('', map { if_(!$_->{comment}, "$_->{key} $_->{value}\n") } @config) if eof; + } $file; +} + +sub get_key_settings { + my ($connection) = @_; + my %ciphers = get_ciphers(); + my @types = ( + pki => N("X509 Public Key Infrastructure"), + static => N("Static Key"), + ); + my $pkcs11_separator = '/'; + my $tokens = $connection->get_pkcs11_tokens; + my %types = @types; + [ + { + label => N("Type"), + val => \$connection->{type}, + list => first(list2kv(@types)), + format => sub { $types{$_[0]} }, + }, + (supports_pkcs11() ? { + label => "PKCS #11 token", + type => 'list', + list => [ undef, @{$tokens->{objects}} ], + format => sub { $_[0] ? join($pkcs11_separator, + $tokens->{slots}{$_[0]{slot}}{label} || $_[0]{slot}, + $_[0]{label} || $_[0]{id}) + : N("None") }, + val => \$connection->{pkcs11_object}, + separator => $pkcs11_separator, + allow_empty_list => 1, + disabled => sub { $connection->{type} ne 'pki' || $connection->{cert_file} || $connection->{key_file} || $connection->{pkcs12_file} }, + } : ()), + { + label => "PKCS #12", + type => 'file', + val => \$connection->{pkcs12_file}, + disabled => sub { $connection->{type} ne 'pki' || $connection->{cert_file} || $connection->{key_file} || $connection->{pkcs11_object} }, + }, + { + label => + #-PO: please don't translate the CA acronym + N("Certificate Authority (CA)"), + type => 'file', + val => \$connection->{ca_file}, + disabled => sub { $connection->{type} ne 'pki' }, + }, + { + label => N("Certificate"), + type => 'file', + val => \$connection->{cert_file}, + disabled => sub { $connection->{type} ne 'pki' || $connection->{pkcs11_object} || $connection->{pkcs12_file} }, + }, + { + label => N("Key"), + type => 'file', + val => \$connection->{key}, + disabled => sub { $connection->{type} eq 'pki' && ($connection->{pkcs11_object} || $connection->{pkcs12_file}) }, + }, + { + label => N("TLS control channel key"), + type => 'file', + val => \$connection->{'tls-auth'}, + disabled => sub { $connection->{type} ne 'pki' }, + advanced => 1, + }, + { + label => N("Key direction"), + type => 'list', + val => \$connection->{key_direction}, + list => [ undef, 0, 1 ], + format => sub { defined($_[0]) ? $_[0] : N("None") }, + advanced => 1, + }, + { + text => N("Authenticate using username and password"), + type => 'bool', + val => \$connection->{'auth-user-pass'}, + advanced => 1, + }, + { + text => N("Check server certificate"), + type => 'bool', + val => \$connection->{check_server}, + advanced => 1, + }, + { + label => N("Cipher algorithm"), + type => 'list', + val => \$connection->{cipher}, + list => [ '', keys %ciphers ], + format => sub { exists $ciphers{$_[0]} ? $ciphers{$_[0]} : N("Default") }, + advanced => 1, + }, + { + label => N("Size of cipher key"), + val => \$connection->{keysize}, + advanced => 1, + disabled => sub { !$connection->{cipher} || $connection->{cipher} eq 'none' }, + }, + ]; +} + +sub get_settings { + my ($connection) = @_; + my @addressing = ( + automatic => N("Get from server"), + manual => N("Manual configuration"), + ); + my %addressing = @addressing; + [ + { + label => N("Gateway"), + val => \$connection->{gateway}, + }, + { + label => N("Gateway port"), + val => \$connection->{port}, + advanced => 1, + }, + { + label => N("IP address"), + val => \$connection->{addressing}, + list => first(list2kv(@addressing)), + format => sub { $addressing{$_[0]} }, + }, + { + label => N("Local IP address"), + val => \$connection->{local_ip}, + disabled => sub { $connection->{addressing} ne 'manual' }, + }, + { + label => N("Remote IP address"), + val => \$connection->{remote_ip}, + disabled => sub { $connection->{addressing} ne 'manual' }, + }, + { + text => N("Use TCP protocol"), + type => 'bool', + val => \$connection->{tcp}, + advanced => 1, + }, + { + label => N("Virtual network device type"), + type => 'list', + list => [ 'tun', 'tap' ], + val => \$connection->{dev_type}, + advanced => 1, + }, + { + label => N("Virtual network device number (optional)"), + val => \$connection->{dev_number}, + advanced => 1, + }, + ]; +} + +my $lib = arch() =~ /x86_64/ ? "lib64" : "lib"; +my $openvpn_default_pkcs11_provider = find { -e $_ } ( + "/usr/local/$lib/libetpkcs11.so", + "/usr/$lib/opensc-pkcs11.so", +); + +my $supports_pkcs11; +sub supports_pkcs11 { + if (!defined $supports_pkcs11) { + require run_program; + $supports_pkcs11 = to_bool(run_program::rooted($::prefix, '/usr/sbin/openvpn', '--show-pkcs11-slots', '')); + } + $supports_pkcs11; +} + +sub get_pkcs11_tokens { + my ($_class, $o_no_cache) = @_; + cache_pkcs11_tokens() if !defined $pkcs11_tokens && !$o_no_cache; + $pkcs11_tokens; +} + +sub cache_pkcs11_tokens { + $pkcs11_tokens = { slots => {}, objects => [] }; + my $slot_id; + foreach (run_program::rooted_get_stdout($::prefix, '/usr/bin/pkcs11-tool', '--module', $openvpn_default_pkcs11_provider, '-L')) { + if (/^Slot\s+(\d+)\s+(.+)$/) { + $slot_id = $2 ne '(empty)' ? $1 : undef; + $pkcs11_tokens->{slots}{$slot_id}{name} = $2 if defined $slot_id; + } elsif (/^\s+token\s+label:\s+(.+)$/) { + $pkcs11_tokens->{slots}{$slot_id}{label} = $1 if defined $slot_id; + } elsif (/^\s+flags:\s*(.*)/) { + my @flags = split(/\s*,\s*/, $1); + if (defined $slot_id && !member("token present", @flags)) { + delete $pkcs11_tokens->{slots}{$slot_id}; + undef $slot_id; + } + } + } + foreach $slot_id (keys %{$pkcs11_tokens->{slots}}) { + my ($type, $label); + my @stdout; #- do rooted_get_stdout manually because pkcs11-tool may exit with non-zero code with proprietary modules + run_program::rooted($::prefix, '/usr/bin/pkcs11-tool', '>', \@stdout, '--module', $openvpn_default_pkcs11_provider, '-O', '--slot', $slot_id); + foreach (@stdout) { + if (/^(\S.*?)\s+Object/) { + $type = $1; + undef $label; + } elsif (/^\s+label:\s+(.+)$/) { + $label = $1; + } elsif (/^\s+ID:\s+(.+)$/ && $type eq 'Public Key') { + push @{$pkcs11_tokens->{objects}}, { id => $1, label => $label, slot => $slot_id }; + } + } + } +} + +sub build_config { + my ($connection) = @_; + ( + { key => 'client', comment => to_bool($connection->{secret_file}) }, + { key => 'proto', $connection->{tcp} ? (value => 'tcp') : (comment => 1) }, + { key => 'dev', value => $connection->{dev_type} . $connection->{dev_number} }, + { key => 'remote', value => join(' ', $connection->{gateway}, if_($connection->{port}, $connection->{port})) }, + (map { +{ key => $_, $connection->{$_ . '_file'} ? (value => $connection->{$_ . '_file'}) : (comment => 1) } } qw(ca cert key pkcs12 secret)), + { key => 'pkcs11-providers', $connection->{pkcs11_object} ? (value => $openvpn_default_pkcs11_provider) : (comment => 1) }, + { key => 'pkcs11-slot-type', $connection->{pkcs11_object} ? (value => 'id') : (comment => 1) }, + { key => 'pkcs11-slot', $connection->{pkcs11_object} ? (value => $connection->{pkcs11_object}{slot}) : (comment => 1) }, + { key => 'pkcs11-id-type', $connection->{pkcs11_object} ? (value => 'id') : (comment => 1) }, + { key => 'pkcs11-id', $connection->{pkcs11_object} ? (value => $connection->{pkcs11_object}{id}) : (comment => 1) }, + { key => 'tls-auth', $connection->{'tls-auth'} ? (value => join(' ', $connection->{'tls-auth'}, if_($connection->{key_direction}, $connection->{key_direction}))) : (comment => 1) }, + { key => 'ns-cert-type', $connection->{check_server} ? (value => 'server') : (comment => 1) }, + { key => 'auth-user-pass', comment => !$connection->{'auth-user-pass'} }, + { key => 'ifconfig', $connection->{addressing} eq 'manual' ? + (value => join(' ', $connection->{local_ip}, $connection->{remote_ip})) : (comment => 1) }, + { key => 'cipher', $connection->{cipher} ? (value => $connection->{cipher}) : (comment => 1) }, + { key => 'keysize', $connection->{keysize} ? (value => $connection->{keysize}) : (comment => 1) }, + ); +} + +sub get_ciphers() { + my @ciphers = chomp_(`/usr/sbin/openvpn --show-ciphers`); + #- drop header + shift @ciphers while $ciphers[0] =~ /^\S/; + none => N("None"), map { if_($_, first(split(' ', $_)), $_) } @ciphers; +} + +sub start { + my ($connection, $o_in) = @_; + $connection->read_config if keys %$connection <= 1; + my %interactive_passwords = if_($o_in, ( + if_($connection->{'auth-user-pass'}, 'Auth' => 1), + if_($connection->{pkcs11_object}, 'Token' => 1), + )); + my $port = 2222; + my $started = $connection->_run('start', + if_(%interactive_passwords, + '--management', "127.0.0.1", $port, + '--management-query-passwords', + )); + $started && (!%interactive_passwords || $connection->ask_passwords($o_in, $port, \%interactive_passwords)); +} + +sub ask_passwords { + my ($_connection, $in, $port, $interactive_passwords) = @_; + require Net::Telnet; + my $t = new Net::Telnet; + $t->open(host => "localhost", port => $port, errmode => "return"); + my $wait; + while (1) { + $wait ||= $in->wait_message(N("VPN connection"), N("Starting connection..")); + my ($_pre, $match) = $t->waitfor(string => ">PASSWORD:", string => ">NEED-OK:", errmode => "return", + #- don't quit if all interactive passwords have been entered + #- in case some passwords are incorrect + #- though, use a smaller timeout + timeout => (%$interactive_passwords ? 20 : 5)); + if (!defined $match) { + my $msg = $t->errmsg; + #- no more interactive password is required, success + $t->close, return 1 if $msg =~ /timed-out/ && !%$interactive_passwords; + $t->close, return; #- potential failure + } elsif ($match eq ">NEED-OK:") { + my ($type, $msg) = $t->getline =~ /'(.*)'.* MSG:/; + undef $wait; + my $ret = $in->ask_okcancel(N("VPN connection"), $type eq 'token-insertion-request' ? + N("Please insert your token") : + $msg); + $t->print(qq(needok "$type" ) . ($ret ? "ok" : "cancel")); + $t->close, return if !$ret; + } elsif ($match eq ">PASSWORD:") { + my ($full_type) = $t->getline =~ /'(.*)'/; + #- assume type is "Auth" if not token + my $type = $full_type =~ /\btoken$/ ? 'Token' : 'Auth'; + my ($username, $password); + undef $wait; + my $ret = $in->ask_from(N("VPN connection"), '', $type eq 'Token' ? [ + { label => N("PIN number"), val => \$password, hidden => 1 } + ] : [ + { label => N("Account Login (user name)"), val => \$username }, + { label => N("Account Password"), val => \$password, hidden => 1 }, + ]); + if ($ret) { + delete $interactive_passwords->{$type}; + $t->print(qq(username "$full_type" "$username")) if $username; + $t->print(qq(password "$full_type" "$password")); + } else { + $t->close, return; + } + } + } +} + +1; diff --git a/lib/network/vpn/vpnc.pm b/lib/network/vpn/vpnc.pm new file mode 100644 index 0000000..f0c8369 --- /dev/null +++ b/lib/network/vpn/vpnc.pm @@ -0,0 +1,74 @@ +package network::vpn::vpnc; + +use base qw(network::vpn); + +use strict; +use common; + +sub get_type { 'vpnc' } +sub get_description { N("Cisco VPN Concentrator") } +sub get_packages { 'vpnc' } + +sub read_config { + my ($connection) = @_; + my @fields = group_by2(list_fields($connection)); + foreach (cat_($connection->get_config_path)) { + foreach my $field (@fields) { + # all strings start exactly one space after the keyword string + /^$field->[0] (.*)/ and ${$field->[1]{val}} = $1; + } + } +} + +sub write_config { + my ($connection) = @_; + output_with_perm($connection->get_config_path, 0600, map { + if_(${$_->[1]{val}}, $_->[0], ' ', ${$_->[1]{val}}, "\n"); + } group_by2(list_fields($connection))); +} + +sub get_settings { + my ($connection) = @_; + second(list2kv(list_fields($connection))); +} + +sub list_fields { + my ($connection) = @_; + ( + 'IPSec gateway' => { + label => N("Gateway"), + val => \$connection->{gateway}, + }, + 'IPSec ID' => { + label => N("Group name"), + val => \$connection->{id}, + }, + 'IPSec secret' => { + label => N("Group secret"), + val => \$connection->{secret}, + hidden => 1, + }, + 'Xauth username' => { + label => N("Username"), + val => \$connection->{username}, + }, + 'Xauth password' => { + label => N("Password"), + val => \$connection->{password}, + hidden => 1, + }, + 'UDP Encapsulate' => { + text => N("Use Cisco-UDP encapsulation"), + type => 'bool', + val => \$connection->{udp}, + advanced => 1, + }, + 'UDP Encapsulation Port' => { + label => N("Use specific UDP port"), + val => \$connection->{udp_port}, + advanced => 1, + }, + ); +} + +1; diff --git a/lib/network/wireless.pm b/lib/network/wireless.pm deleted file mode 100644 index 513c8a9..0000000 --- a/lib/network/wireless.pm +++ /dev/null @@ -1,239 +0,0 @@ -package network::wireless; - -use strict; -use common; - -our %wireless_enc_modes = ( - none => N_("None"), - open => N_("Open WEP"), - restricted => N_("Restricted WEP"), - 'wpa-psk' => N_("WPA Pre-Shared Key"), -); - -my $wpa_supplicant_conf = "/etc/wpa_supplicant.conf"; - -sub is_old_rt2x00 { - my ($module) = @_; - member($module, qw(rt2400 rt2500)); -} - -sub is_wpa_supplicant_blacklisted { - my ($module) = @_; - is_old_rt2x00($module); -} - -sub get_hex_key { - my ($key) = @_; - if ($key =~ /^([[:xdigit:]]{4}[\:-]?)+[[:xdigit:]]{2,}$/) { - $key =~ s/[\:-]//g; - return lc($key); - } -} - -sub convert_wep_key_for_iwconfig { - #- 5 or 13 characters, consider the key as ASCII and prepend "s:" - #- else consider the key as hexadecimal, do not strip dashes - #- always quote the key as string - my ($real_key, $restricted) = @_; - my $key = get_hex_key($real_key) || "s:$real_key"; - $restricted ? "restricted $key" : "open $key"; -} - -sub get_wep_key_from_iwconfig { - #- strip "s:" if the key is 5 or 13 characters (ASCII) - #- else the key as hexadecimal, do not modify - my ($key) = @_; - my ($mode, $real_key) = $key =~ /^(?:(open|restricted)\s+)?(.*)$/; - $real_key =~ s/^s://; - ($real_key, $mode eq 'restricted'); -} - -sub convert_key_for_wpa_supplicant { - my ($key) = @_; - get_hex_key($key) || qq("$key"); -} - -sub wlan_ng_needed { - my ($module) = @_; - $module =~ /^prism2_/; -} - -#- FIXME: to be improved (quotes, comments) and moved in common files -sub wlan_ng_update_vars { - my ($file, $vars) = @_; - substInFile { - while (my ($key, $value) = each(%$vars)) { - s/^#?\Q$key\E=(?:"[^#]*"|[^#\s]*)(\s*#.*)?/$key=$value$1/ and delete $vars->{$key}; - } - $_ .= join('', map { "$_=$vars->{$_}\n" } keys %$vars) if eof; - } $file; -} - -sub wlan_ng_configure { - my ($essid, $key, $device, $module) = @_; - my $wlan_conf_file = "$::prefix/etc/wlan/wlan.conf"; - my @wlan_devices = split(/ /, (cat_($wlan_conf_file) =~ /^WLAN_DEVICES="(.*)"/m)[0]); - push @wlan_devices, $device unless member($device, @wlan_devices); - #- enable device and make it use the choosen ESSID - wlan_ng_update_vars($wlan_conf_file, - { - WLAN_DEVICES => qq("@wlan_devices"), - "SSID_$device" => qq("$essid"), - "ENABLE_$device" => "y" - }); - - my $wlan_ssid_file = "$::prefix/etc/wlan/wlancfg-$essid"; - #- copy default settings for this ESSID if config file does not exist - -f $wlan_ssid_file or cp_f("$::prefix/etc/wlan/wlancfg-DEFAULT", $wlan_ssid_file); - - #- enable/disable encryption - wlan_ng_update_vars($wlan_ssid_file, - { - (map { $_ => $key ? "true" : "false" } qw(lnxreq_hostWEPEncrypt lnxreq_hostWEPDecrypt dot11PrivacyInvoked dot11ExcludeUnencrypted)), - AuthType => $key ? qq("sharedkey") : qq("opensystem"), - if_($key, - dot11WEPDefaultKeyID => 0, - dot11WEPDefaultKey0 => qq("$key") - ) - }); - #- hide settings for non-root users - chmod 0600, $wlan_conf_file; - chmod 0600, $wlan_ssid_file; - - #- apply settings on wlan interface - require services; - services::restart($module eq 'prism2_cs' ? 'pcmcia' : 'wlan'); -} - -sub wpa_supplicant_get_driver { - my ($module) = @_; - $module =~ /^hostap_/ ? "hostap" : - $module eq "prism54" ? "prism54" : - $module =~ /^ath_/ ? "madwifi" : - $module =~ /^at76c50|atmel_/ ? "atmel" : - $module eq "ndiswrapper" ? "ndiswrapper" : - "wext"; -} - -sub wpa_supplicant_add_network { - my ($essid, $enc_mode, $key) = @_; - my $conf = wpa_supplicant_read_conf(); - my $network = { - ssid => qq("$essid"), - scan_ssid => 1, - }; - - if ($enc_mode eq 'wpa-psk') { - $network->{psk} = convert_key_for_wpa_supplicant($key); - } else { - $network->{key_mgmt} = 'NONE'; - if (member($enc_mode, qw(open restricted))) { - put_in_hash($network, { - wep_key0 => convert_key_for_wpa_supplicant($key), - wep_tx_keyidx => 0, - auth_alg => $enc_mode eq 'restricted' ? 'SHARED' : 'OPEN', - }); - } - } - - @$conf = difference2($conf, [ wpa_supplicant_find_similar($conf, $network) ]); - push @$conf, $network; - wpa_supplicant_write_conf($conf); -} - -sub wpa_supplicant_find_similar { - my ($conf, $network) = @_; - grep { - my $current = $_; - any { exists $network->{$_} && $network->{$_} eq $current->{$_} } qw(ssid bssid); - } @$conf; -} - -sub wpa_supplicant_read_conf() { - my @conf; - my $network; - foreach (cat_($::prefix . $wpa_supplicant_conf)) { - if ($network) { - #- in a "network = {}" block - if (/^\s*(\w+)=(.*?)(?:\s*#.*)?$/) { - $network->{$1} = $2; - } elsif (/^\}/) { - #- end of network block - push @conf, $network; - undef $network; - } - } elsif (/^\s*network={/) { - #- beginning of a new network block - $network = {}; - } - } - \@conf; -} - -sub wpa_supplicant_write_conf { - my ($conf) = @_; - my $buf; - my @conf = @$conf; - my $network; - foreach (cat_($::prefix . $wpa_supplicant_conf)) { - if ($network) { - #- in a "network = {}" block - if (/^\s*(\w+)=(.*)$/) { - push @{$network->{entries}}, { key => $1, value => $2 }; - member($1, qw(ssid bssid)) and $network->{$1} = $2; - } elsif (/^\}/) { - #- end of network block, write it - $buf .= "network={$network->{comment}\n"; - - my $new_network = first(wpa_supplicant_find_similar(\@conf, $network)); - foreach (@{$network->{entries}}) { - my $key = $_->{key}; - if ($new_network) { - #- do not write entry if not provided in the new network - exists $new_network->{$key} or next; - #- update value from the new network - $_->{value} = delete $new_network->{$key}; - } - $buf .= " "; - $buf .= "$key=$_->{value}" if $key; - $buf .= "$_->{comment}\n"; - } - if ($new_network) { - #- write new keys - while (my ($key, $value) = each(%$new_network)) { - $buf .= " $key=$value\n"; - } - } - $buf .= "}\n"; - $new_network and @conf = grep { $_ != $new_network } @conf; - undef $network; - } else { - #- unrecognized, keep it anyway - push @{$network->{entries}}, { comment => $_ }; - } - } else { - if (/^\s*network={/) { - #- beginning of a new network block - $network = {}; - } else { - #- keep other options, comments - $buf .= $_; - } - } - } - - #- write remaining networks - foreach (@conf) { - $buf .= "\nnetwork={\n"; - while (my ($key, $value) = each(%$_)) { - $buf .= " $key=$value\n"; - } - $buf .= "}\n"; - } - - output($::prefix . $wpa_supplicant_conf, $buf); - #- hide keys for non-root users - chmod 0600, $::prefix . $wpa_supplicant_conf; -} - -1; |