problem probing network interfaces

From: Chris Hanson (cph@zurich.ai.mit.edu)
Date: Mon May 19 2003 - 13:47:36 EST


   Date: Thu, 08 May 2003 10:29:06 -0700 (PDT)
   From: "David S. Miller" <davem@redhat.com>

      From: Chris Hanson <cph@zurich.ai.mit.edu>
      Date: Thu, 08 May 2003 14:34:21 -0400

      For example, is it sufficient to just set IFF_UP and leave the
      other flags off?

   Setting this interface flag from userspace should work.

OK, but... (I bet you thought this conversation was finished :)

This seems to work most of the time, except for one of my users. He's
using the sis900 driver in kernel 2.4.21-rc1. When I don't force the
interface up, my code is able to detect link beat with no trouble.
When I _do_ force the interface up, it doesn't.

Any ideas why this would be true? I've tried a number of different
things and have failed to come up with a working configuration, other
than to leave the interface down when it is already down.

I did notice that the sis900 doesn't seem to immediately detect
link-beat when it is up, instead deferring to a timer event, but
sleeping for a full second after bringing the interface up didn't
change anything.

FYI, here is my current detection code. Perhaps there's something
wrong with it, although it's quite similar to mii-diag.

Chris

static unsigned int
get_link_status (int fd, const char * if_name, unsigned int * result_r)
{
  struct ifreq ifr;
  u16 * data = ((u16 *) (& (ifr . ifr_data)));
  unsigned int if_flags;
  int up_p;
  int run_p;
  int conn_p;
  unsigned int retval;

  strncpy ((ifr . ifr_name), if_name, IFNAMSIZ);
  if ((ioctl (fd, SIOCGIFFLAGS, (&ifr))) < 0)
    return (errno);
  if_flags = (ifr . ifr_flags);
  up_p = ((if_flags & IFF_UP) != 0);
  run_p = ((if_flags & IFF_RUNNING) != 0);

  /* As of 2.4.20, interfaces must be up in order to be interrogated. */
  if (!up_p)
    {
      strncpy ((ifr . ifr_name), if_name, IFNAMSIZ);
      (ifr . ifr_flags) = IFF_UP;
      ioctl (fd, SIOCSIFFLAGS, (&ifr));
    }

  strncpy ((ifr . ifr_name), if_name, IFNAMSIZ);
  (data[1]) = 1; /* read Basic Mode Status Register */
  if ((ioctl (fd, SIOCGMIIPHY, (&ifr))) < 0)
    retval = errno;
  else if ((data[3]) == 0xFFFF)
    /* Interface no longer available. */
    retval = ENODEV;
  else
    {
      /* Check for:
         0x0002 clear = no jabber
         0x0004 set = link up
         0x0010 clear = no remote fault */
      conn_p = (((data[3]) & 0x0016) == 0x0004);
      retval = 0;
    }

  /* Restore original interface flags. */
  if (!up_p)
    {
      strncpy ((ifr . ifr_name), if_name, IFNAMSIZ);
      (ifr . ifr_flags) = if_flags;
      ioctl (fd, SIOCSIFFLAGS, (&ifr));
    }

  if (retval == 0)
    (*result_r)
      = ((up_p ? STATUS_UP : 0)
         | (run_p ? STATUS_RUNNING : 0)
         | (conn_p ? STATUS_CONNECTED : 0));
  return (retval);
}
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html



This archive was generated by hypermail 2b29 : Fri May 23 2003 - 22:00:02 EST