This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ioctl(SIOCGIFFLAGS) uses the interface address instead of name?


Hello,

ioctl(SIOCGIFFLAGS) doesn't work the way I expected it to : it
apparently uses as an input the ifr_addr field of the output union
present in struct ifreq, instead of the ifr_name (first union in that
struct) which is used by the 2 Unices I have access to (Linux and
Solaris).

The code I'm using (written for Unix) uses a separate memory area for the
first call to ioctl(SIOCGIFCONF) and the following calls to
ioctl(SIOCGIFFLAGS). It reads more or less like:

   char buf[BUFSIZ];
   struct ifconf ic;

   ic.ifc_len = sizeof buf;
   ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
   ioctl(SIOCGIFCONF, &ic)

   for (i = 0; i < ic.ifc_len;) {
       struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
       struct ifreq ifr;

       i += (have_sa_len) ? some_calculation_involving_sa_len : sizeof(struct ifreq);

       strcpy (ifr.ifr_name, ifp -> ifr_name);
       ioctl (sock, SIOCGIFFLAGS, &ifr);
       if (ifr.ifr_flags & IFF_LOOPBACK) {
	  /* process loopback netifs a special way */;
       } else {
	  /* process other interfaces a different way */;
       }
   }

Written like this, the code doesn't correctly detect the loopback interface
when run on Cygwin (on the 2 Unix platforms I otherwise use, all is fine).

Thanks to the availabilite of Cygwin's source code, I found in
cygwin/fhandler_socket.cc one explaination (code slightly edited for
the discussion's purpose):

    int
    fhandler_socket::ioctl (unsigned int cmd, void *p)
    {
      int res;
      struct ifconf ifc, *ifcp;
      struct ifreq *ifr, *ifrp;
        ...
      switch (cmd)
    	{
        ...
    	case SIOCGIFFLAGS:
    	  ifr = (struct ifreq *) p;
    	  if (ifr == 0)
    	    {
    	      set_errno (EINVAL);
    	      return -1;
    	    }
    	  ifr->ifr_flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING;
    	  if (ntohl (((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr)
    	      == INADDR_LOOPBACK)
    	    ifr->ifr_flags |= IFF_LOOPBACK;
    	  else
    	    ifr->ifr_flags |= IFF_BROADCAST;
    	  res = 0;
    	  break;
        ...
     }

This code doesn't uses the interface name as its input argument, but the
interface address. This code seems to have been written with the implicit
assumption that the ifreq object passed to it is the very same as the one
passed to the SIOCGIFCONF code earlier (in the process' life).

In my case, passing in the name just doesn't work, the caller needs to pass
the address instead, contrary to what seems the general belief.

I modified the test program mentionned in
http://www.cygwin.com/ml/cygwin/2001-05/msg00741.html to pass to
ioctl(SIOCGIFFLAGS) a structure allocated independently of the memory passed
to SIOCGIFCONF and ran it on Solaris 2.8 and Linux 2.4.8 (Mandrake 8.1).
They both base their decision on the interface name instead of the address.

In the cygwin implementation, the loopback interface is totally hand
crafted, with an agreed-upon name of 'lo'. Why not base the decision on this
name? Anyway the input to the various ioctl(SIOCGIFFLAGS), MASK, ... calls
using a struct ifreq is an interface name, not the address.

Fixing this would help decrease the (programming) distance between this
emulated environment and the "real" stuff, increasing application's
portability.

I would thus propose this modification to fhandler_socket.cc (change that
shouldn't break applications relying on the until-now cygwin behavior) :

--- fhandler_socket.cc  Sat Jul  6 08:05:32 2002
+++ fhandler_socket.cc.new      Thu Oct 10 19:05:33 2002
@@ -996,7 +996,8 @@
          return -1;
        }
       ifr->ifr_flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING;
-      if (ntohl (((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr)
+      if ((! strncmp(ifr->ifr_name, "lo", 2))
+         || ntohl (((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr)
          == INADDR_LOOPBACK)
        ifr->ifr_flags |= IFF_LOOPBACK;
       else

I noticed that a few people over the years fell into something that
could be related as mentionned in the following past emails:

http://www.cygwin.com/ml/cygwin/2001-05/msg00741.html
http://www.cygwin.com/ml/cygwin/1999-06/msg00027.html
http://www.cygwin.com/ml/cygwin/1999-06/msg00046.html
				 and
http://www.cygwin.com/ml/cygwin/1999-06/msg00077.html

The last one is especially interesting : the test program has 2 different
behavior whether run directly from the shell or from gdb.  In the test
program provided in the message body, the same memory area is used in all
the ioctl calls: to SIOCGIFCONF and to the (many) SIOCGIFFLAGS, thus
"corrupting" the 'sa_family' field of the interface's sockaddr (ifreq hold a
UNION of the various answer, it's not a STRUCT).

Thanks for any help/insight/comment you may provide.


Gilles                (Gilles.Courcoux@Col.Bsf.Alcatel.FR)


--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]