summaryrefslogtreecommitdiffstats
path: root/perl-install/network/ethernet.pm
blob: 600ec2c9956fffc579583ecbd8019bcb2d7b9e7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package network::ethernet; # $Id$

use c;
use network::network;
use modules;
use modules::interactive;
use detect_devices;
use common;
use run_program;
use network::tools;
use vars qw(@ISA @EXPORT);

@ISA = qw(Exporter);
@EXPORT = qw(get_eth_categories);

sub write_ether_conf {
    my ($in, $modules_conf, $netcnx, $netc, $intf) = @_;
    configureNetwork2($in, $modules_conf, $::prefix, $netc, $intf);
    $netc->{NETWORKING} = "yes";
    if ($netc->{GATEWAY} || any { $_->{BOOTPROTO} =~ /dhcp/ } values %$intf) {
	$netcnx->{type} = 'lan';
	$netcnx->{NET_DEVICE} = $netc->{NET_DEVICE} = '';
	$netcnx->{NET_INTERFACE} = 'lan'; #$netc->{NET_INTERFACE};
    }
    $::isStandalone and $modules_conf->write;
    1;
}


sub mapIntfToDevice {
    my ($interface) = @_;
    my $hw_addr = c::getHwIDs($interface);
    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() : {};
}


sub get_eth_categories() {
    'network/main|gigabit|pcmcia|usb|wireless|firewire';
}

# 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;
        # 0) get interface's driver through ETHTOOL ioctl or module aliases:
        my $a = c::getNetDriver($interface) || $modules_conf->get_alias($interface);
        my %fixes = (
                     "p80211_prism2_usb" => 'prism2_usb',
                     "ip1394" => "eth1394",
                    );
        $a = $fixes{$a} if $fixes{$a};
        # 1) 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 {
            # 2) 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};
        }
        # 3) try to match a device through sysfs for driver & device description:
        #     (eg: ipw2100 driver for intel centrino do not support ETHTOOL)
        if (!$description) {
            my $drv = readlink("/sys/class/net/$interface/driver");
            if ($drv && $drv =~ s!.*/!!) {
                $a = $drv;
                my %l;
                my %sysfs_fields = (id => "device", subid => "subsystem_device", vendor => "vendor", subvendor => "subsystem_vendor");
                $l{$_} = hex(chomp_(cat_("/sys/class/net/$interface/device/" . $sysfs_fields{$_}))) foreach keys %sysfs_fields;
                my @cards = grep { my $dev = $_; every { $dev->{$_} eq $l{$_} } keys %l } detect_devices::probeall();
                $description = $cards[0]{description} if @cards == 1;
            }
        }
        # 4) 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) = @_;
    `LC_ALL= LANG= $::prefix/sbin/ip -o link show $intf 2>/dev/null` =~ m|.*link/(\S+)\s([0-9a-z:]+)\s|;
}

#- write interfaces MAC address in iftab
sub update_iftab() {
    foreach my $intf (detect_devices::getNet()) {
        my ($link_type, $mac_address) = get_eth_card_mac_address($intf) or next;
        my $descriptor = ${{ ether => 'mac', ieee1394 => 'mac_ieee1394' }}{$link_type} or next;
        substInFile {
            s/^$intf\s+.*\n//;
            $_ .= qq($intf\t$descriptor $mac_address\n) if eof
        } "$::prefix/etc/iftab";
    }
}

# automatic net aliases configuration
sub configure_eth_aliases {
    my ($modules_conf) = @_;
    my @pcmcia = detect_devices::pcmcia_probe();
    foreach my $card (get_eth_cards($modules_conf)) {
        if (any { $_->{device} eq $card->[0] } @pcmcia) {
            #- don't write aliases for pcmcia cards, or cardmgr won't be loaded
            $modules_conf->remove_alias($card->[0]);
        } else {
            $modules_conf->set_alias($card->[0], $card->[1]);
        }
    }
}

1;