While writing this article, with the most recent kernel installed on my machine, however, I discovered I had to add the ETHTOOL method.
After adding ETHTOOL, I then modified the program and wrote each interface method as a subroutine. The modified program tries one method, and if it fails, attempts the other. The third method predates the MII API, and I have not yet run into a machine on which I have needed it, so the code is not included.
The information on using the MII interface was acquired mainly by examining the mii-diag program (ftp.scyld.com/ pub/diag/mii-diag.c) written by Donald Becker, which I found on Scyld Computing Corporation's Web site. This site also contains an excellent page (www.scyld.com/diag/ mii-status.html) explaining the details of the MII status words that the ioctl functions may return. Here, however, I focus on the ETHTOOL interface because it is the newer method. The program and both interfaces are available from the Linux Journal FTP site at ftp.ssc.com/pub/lj/listings/ issue117/6908.tgz.
Information on using the ETHTOOL API also was acquired by scouring various pieces of source code, not the least of which was the source code for the network interface drivers themselves—particularly eepro100.c. Also helpful was an e-mail written by Tim Hockin that I found while Googling.
In writing my program, I set the default interface to eth0 unless a parameter was passed to the program. The interface ID is stored in ifname. Because the ioctl commands I use are specific to network interfaces, using some other device likely will cause a "cannot determine status" to be returned.
Before calling ioctl we need a file handle, so we first must open a socket:
if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
In the standard try-to-check-for-all-errors C coding style, I placed this inside an if statement that simply prints an error and terminates the program, returning a -1 if the socket does not open properly. For my purposes, I would rather report errors in determining status as a lack of a link rather than as a presence of one, so a found link is reported as 0 and not found is reported as 1.
The new ETHTOOL API for interfacing to the driver has made determining the status of the link much easier than did the previous method. ioctl was implemented for ETHTOOL interfaces such that there is now only ONE ioctl command, SIOCETHTOOL (which specifies that the call is an ETHTOOL command), and the data block passed then contains the specific subcommand for the ETHTOOL interface.
The standard ioctl data structure (type ifreq) requires two additional items: the name of the interface to which the command should be applied and an address of a structure (type ethtool_value) in which to store the specific command as well as the returned information.
The structures and most other information (including the commands available) are located in the ethtool.h header file.
The command that I needed was ETHTOOL_GLINK, documented as "get link status", which I stored in edata.cmd:
edata.cmd = ETHTOOL_GLINK;
The name of the interface and the address of the edata structure both need to be placed into the ifreq structure:
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1); ifr.ifr_data = (char *) &edata;
At this point, all that remains is making the ioctl call, checking the return value (to be sure the command type was allowed) and checking the data in the structure pointed to by the returned pointer to see if the link is up or down:
printf("ETHTOOL_GLINK failed: %s\n", strerror(errno)); return 2;
In this case, my code returns a 0 for link up, a 1 for link down and a 2 for undetermined or failure. This code allows me to call this function from my rc.local, bring the interface up and either call dhcpcd or pump to get an IP address only if the system is plugged in to a functioning hub/switch. Here is the relevant section of rc.local:
/root/sense_link/sense_link | logger if /root/sense_link/sense_link > /dev/null; then logger "No link sense -- downing eth0" /sbin/ifconfig eth0 down else logger "Sensed link - dhcping eth0" /sbin/dhcpcd eth0
First, the output of sense_link is sent to the system log. Then, if no link was sensed on eth0, or if it could not be determined, a message is written to the log and eth0 is taken down. If a link was sensed, dhcpcd is executed on eth0.
Once this is implemented, my rc.local file now executes quite quickly when no network cable is plugged in or when a DHCP server is active and found. The only time I still experience significant delays is if I am plugged in to a network where there is no active DHCP server.
I haven't yet tried this code with my 802.11b card to see if it can detect a link on it before attempting to contact a DHCP server, because I usually only have the PCMCIA card plugged in when I am in a location that I know has a server. It would be an interesting experiment and a useful extension, however, for an interested party.H
Lisa Corsetti presently is a software architect as well as the president of Anteil, Inc., a consulting firm that focuses on custom Web-based applications for various industries and government. Lisa received a BS in Electrical and Computer Engineering from Drexel University
Over 1 5 classes in:
► Emerging Techno logics Modeling, Design fi Quality
* People, Process & Methods Web Service5 Technologies
► Requirements a Analysis
X SUPER EARLY BJRD
Register by January 16 and . save up to
f EARLY BIRD > DISCOUNT
Register by February 13 and save up to
NEW Expo, Panels, Case Studies, Roundtabtes, BOFhs and exciting Special Events
MARCH 15-19, 2004, SANTA CLARA, CA
Was this article helpful?