Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Date: Wed, 16 Oct 2002 15:09:24 +0200 (MEST) Message-Id: <200210161309.PAA08417@cu5s138.clb> X-Authentication-Warning: cu5s138.clb: courcoux set sender to Gilles DOT Courcoux AT Col DOT Bsf DOT Alcatel DOT FR using -f From: Gilles Courcoux To: cygwin AT cygwin DOT com Subject: ioctl(SIOCGIFFLAGS) uses the interface address instead of name? Reply-to: Gilles DOT Courcoux AT col DOT bsf DOT alcatel DOT fr X-Virus-Scanned: by amavisd-milter (http://amavis.org/) 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 DOT Courcoux AT Col DOT Bsf DOT Alcatel DOT 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/