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