diff options
Diffstat (limited to 'lib/network/ethernet.pm')
-rw-r--r-- | lib/network/ethernet.pm | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/lib/network/ethernet.pm b/lib/network/ethernet.pm new file mode 100644 index 0000000..c97f45f --- /dev/null +++ b/lib/network/ethernet.pm @@ -0,0 +1,162 @@ +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; |