/* * Copyright (C) 2006, Intel Corporation * * This file is part of the Linux-ready Firmware Developer Kit * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation;version 2.1 of the License. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* debian has a broken /usr/include/linux/ethtool.h that uses kernel types not userspace safe types */ #define u64 __u64 #define u32 __u32 #define u16 __u16 #define u8 __u8 #include #undef u64 #undef u32 #undef u16 #undef u8 #include #include extern void load_boot_dmesg_buffer(); static void get_dhcp_lease(char *iface) { FILE *file; int success = 0; char *dhclient_cmd; char command[4096]; char *details = strdup(""); /* Get dhclient command */ dhclient_cmd = get_relative_command ("dhclient", NULL); if(dhclient_cmd) { unlink("/var/run/dhclient.pid"); sprintf(command, "%s %s 2> /tmp/dhclient", dhclient_cmd, iface); system(command); file = fopen("/tmp/dhclient", "r"); if (!file) { fprintf(stderr, "WARN: could not read /tmp/dhclient.\n"); return; } while (!feof(file)) { char line[4096]; memset(line, 0, 4096); if (fgets(line, 4095, file)==NULL) break; if (strstr(line, "bound to ")) success = 1; details = scatprintf(details, line); } fclose(file); } else { sprintf(command,"echo dhclient not found >> %s", LFDK_ERRLOG); system(command); report_result("ethernet", WARN, "could not find dhclient exe", details, NULL); } if (success) report_result("ethernet", PASS, "Got a DHCP lease", details, NULL); else report_result("ethernet", WARN, "Got no DHCP lease", details, NULL); free(details); } static void test_iface(char *iface) { int sock; struct ifreq ifr; struct ethtool_value ethtool; struct ethtool_drvinfo driver; time_t start_time, end_time; int ret; int fail = 0; int gotlink = 0; char uri[4096]; memset(&ifr, 0, sizeof(struct ifreq)); memset(ðtool, 0, sizeof(struct ethtool_value)); memset(uri,0,4096); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock<0) return; strcpy(ifr.ifr_name, iface); /* Up the interface, mark the time */ ret = ioctl(sock, SIOCGIFFLAGS, &ifr); if (ret<0) return; ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); ret = ioctl(sock, SIOCSIFFLAGS, &ifr); if (ret<0) return; start_time = time(NULL); end_time = start_time; /* now ... wait for link */ while (time(NULL) - start_time < 25) { ethtool.cmd = ETHTOOL_GLINK; ifr.ifr_data = (void*)ðtool; ret = ioctl(sock, SIOCETHTOOL, &ifr); if (ret<0) return; if (ethtool.data) { /* we have link! */ gotlink=1; end_time = time(NULL); break; } sleep(1); report_testrun_progress( (time(NULL) - start_time)*2+10); } memset(&driver, 0, sizeof(driver)); driver.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (void*) &driver; ret = ioctl(sock, SIOCETHTOOL, &ifr); sprintf(uri,"pci://%s", driver.bus_info); if (gotlink) { char buffer[4096]; sprintf(buffer, "Acquired ethernet link after %i seconds",(int)(end_time-start_time)); report_result("ethernet",INFO, buffer, NULL, uri); } else { report_result("ethernet",FAIL, "Failed to acquire link within 45 seconds", NULL, uri); fail = 1; } close(sock); if (!fail) get_dhcp_lease(iface); } static void check_line(gpointer data, gpointer user_data) { char *line = (char *)data; if (strstr(line, "The EEPROM Checksum Is Not Valid") && strstr(line,"e1000")) report_result("ethernet", FAIL, "E1000 EEPROM checksum is invalid, NIC unusable", line, NULL); if (strstr(line, "e100_eeprom_load: EEPROM corrupted") && strstr(line,"e1000")) report_result("ethernet", FAIL, "E100 EEPROM checksum is invalid, NIC unusable", line, NULL); } int main(int argc, char **argv) { FILE *file; char line[4096]; file = fopen("/proc/net/dev", "r"); if (!file) return 0; start_test("ethernet", "Ethernet functionality", "This test is currently a placeholder for a more advanced ethernet test. " "Currently the only check performed is that a link is acquired within 45 " "seconds of enabling the interface. 45 seconds is close to the value " "most Linux distributions use as timeout value.\n\n" "In the future the plan is to also perform actual data transfer tests " "as part of the ethernet test, to validate interrupt routing and other " "per-NIC behaviors."); while (!feof(file)) { char *c; memset(line, 0, 4096); if (fgets(line, 4095, file)==NULL) break; c = strchr(line, ':'); if (c) *c = 0; c = line; while (*c==' ') c++; if (strstr(c,"eth")) test_iface(c); } fclose(file); load_boot_dmesg_buffer(); if(boot_dmesg != NULL) g_list_foreach(boot_dmesg, check_line, NULL); else fprintf(stderr, "WARN: No boot dmesg found.\n"); finish_test("ethernet"); return 0; }