From: corinna DOT vinschen AT cityweb DOT de (Corinna Vinschen) Subject: B20 patch: extended socket::ioctl functionality 13 Nov 1998 14:30:06 -0800 Message-ID: <364CA894.D47F81C9.cygnus.cygwin32.developers@cityweb.de> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------7201EB56BC7E17190054A4E1" To: cygwin32-developers AT cygnus DOT com This is a multi-part message in MIME format. --------------7201EB56BC7E17190054A4E1 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hi, the following patch (relativ to winsup-981111) is a bit larger. It corrects the ifconfig handling and reads the configuration from registry. The Win95 part isn't tested yet, I don't use Win95. The ioctl commands SIOCGIFADDR, SIOCGIFBRDADDR and SIOCGIFNETMASK are now supported. The function `get_if_flags()' now sets the flags IFF_UP and IFF_RUNNING only, if the interface is really up. Regards, Corinna ChangeLog: ---------- Sun Oct 4 23:58:00 1998 Corinna Vinschen * net.cc (get_if_flags): Checks for a down interface now. Tue Sep 1 20:23:00 1998 Corinna Vinschen * net.cc (get_win95_ifconf): Checks now the registry entries for win95 as described by Tim Newsham (UNTESTED!). * net.cc (fhandler_socket::ioctl): Supports now the ioctl() commands SIOCGIFBRDADDR and SIOCGIFNETMASK for Win95, too. Sun Aug 16 9:45:00 1998 Corinna Vinschen Since Sat Aug 8 1998 * include/asm/socket.h: Added defines for ioctl() calls SIOCGIFADDR, SIOCGIFBRDADDR and SIOCGIFNETMASK. * net.cc (get_winnt_ifconf): Checks now the registry entries instead of calling the poor function get_win95_ifconf(). Added parameter 'int what' for support of new ioctl() calls. * net.cc (fhandler_socket::ioctl): Supports now the ioctl() commands SIOCGIFADDR and only for WinNT SIOCGIFBRDADDR and SIOCGIFNETMASK. --------------7201EB56BC7E17190054A4E1 Content-Type: text/plain; charset=us-ascii; name="socket.h-patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="socket.h-patch" --- include/asm/socket.h.orig Fri Nov 13 20:33:41 1998 +++ include/asm/socket.h Fri Nov 13 20:34:29 1998 @@ -25,6 +25,9 @@ /* Needed for if queries */ #define SIOCGIFCONF _IOW('s', 100, struct ifconf) /* get if list */ #define SIOCGIFFLAGS _IOW('s', 101, struct ifreq) /* Get if flags */ +#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ +#define SIOCGIFBRDADDR _IOW('s', 103, struct ifreq) /* Get if broadcastaddr */ +#define SIOCGIFNETMASK _IOW('s', 104, struct ifreq) /* Get if netmask */ #define SOL_SOCKET 0xffff /* options for socket level */ --------------7201EB56BC7E17190054A4E1 Content-Type: text/plain; charset=us-ascii; name="net.cc-patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="net.cc-patch" --- net.cc.orig Fri Nov 13 20:02:43 1998 +++ net.cc Fri Nov 13 22:44:00 1998 @@ -1090,12 +1090,28 @@ getdomainname (char *domain, int len) * It is unlikely Win95 will ever have more than one netcard, so * just do a gethostbyname. If this succeeds, then we have this * interface plus a loopback. + * + * New version: Now reads all Entries + * "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\NetTrans\*" + * from Registry and uses all entries, which have legal values + * "IPAddress" and "IPMask". */ static int -get_win95_ifconf (struct ifconf *ifc) +get_win95_ifconf (struct ifconf *ifc, int what) { - /* Assume machinename will fit in 255 bytes, we will fail if not.*/ - char name[256]; + HKEY key, subkey; + FILETIME update; + LONG res; + DWORD type, size; + unsigned long lip, lnp; + char ifname[256], ip[256], np[256]; + int cnt = 1; + struct sockaddr_in *sa; + struct ifreq *ifr = ifc->ifc_req; /* Union maps buffer to correct struct */ + char eth[2]; + + eth[0] = '/'; + eth[1] = '\0'; /* Ensure we have space for two struct ifreqs, fail if not. */ if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq))) @@ -1104,41 +1120,95 @@ get_win95_ifconf (struct ifconf *ifc) return -1; } - if (gethostname (name, sizeof (name)) == SOCKET_ERROR) - { - set_winsock_errno (); - return -1; - } - /* Now do the gethostbyname call */ - struct hostent *he = (*i_gethostbyname) (name); - if (he == 0) - { - set_winsock_errno (); - return -1; - } - - struct sockaddr_in *sa; - struct ifreq *ifr = ifc->ifc_req; /* Union maps buffer to correct struct */ /* Set up interface lo0 first */ - ifr++; strcpy (ifr->ifr_name, "lo0"); - memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr)); - sa = (struct sockaddr_in *) &ifr->ifr_addr; + memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK); + break; + case SIOCGIFBRDADDR: + lip = htonl(INADDR_LOOPBACK); + lnp = cygwin_inet_addr ("255.0.0.0"); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0"); + break; + default: + set_errno (EINVAL); + return -1; + } sa->sin_family = AF_INET; sa->sin_port = 0; - sa->sin_addr.s_addr = INADDR_LOOPBACK; - /* Increment and set up the eth0 struct */ - strcpy (ifr->ifr_name, "eth0"); - memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr)); - sa = (struct sockaddr_in *)&ifr->ifr_addr; - sa->sin_family = AF_INET; - sa->sin_port = 0; - sa->sin_addr = *(struct in_addr *) he->h_addr; + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\" + "CurrentControlSet\\" + "Services\\" + "Class\\" + "NetTrans", + 0, KEY_READ, &key) == ERROR_SUCCESS) + { + for (int i = 0; + (res = RegEnumKeyEx (key, i, ifname, + (size = sizeof ifname, &size), + 0, 0, 0, &update)) != ERROR_NO_MORE_ITEMS; + ++i) + { + if (res != ERROR_SUCCESS + || RegOpenKeyEx (key, ifname, 0, + KEY_READ, &subkey) != ERROR_SUCCESS) + continue; + if (RegQueryValueEx (subkey, "IPAddress", 0, + &type, (unsigned char *) ip, + (size = sizeof ip, &size)) == ERROR_SUCCESS + || RegQueryValueEx (subkey, "IPMask", 0, + &type, (unsigned char *) np, + (size = sizeof np, &size)) == ERROR_SUCCESS) + { + if ((caddr_t)++ifr > ifc->ifc_buf + + ifc->ifc_len + - sizeof(struct ifreq)) + break; + ++*eth; + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = cygwin_inet_addr (ip); + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (ip); + lnp = cygwin_inet_addr (np); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr (np); + break; + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + ++cnt; + } + RegCloseKey (subkey); + } + } - /* Set the correct length */ - ifc->ifc_len = 2 * sizeof (struct ifreq); - return 0; + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); + + return 0; } /* Cygwin internal */ @@ -1157,30 +1227,219 @@ get_win95_ifconf (struct ifconf *ifc) * likely than 95 to be multi-homed. * * For now, though, just punt and do the same as on 95. + * + * No! Fixed now! */ static int -get_winnt_ifconf (struct ifconf *ifc) +get_winnt_ifconf (struct ifconf *ifc, int what) { - return get_win95_ifconf (ifc); + HKEY key; + DWORD type, size; + unsigned long lip, lnp; + int cnt = 1; + char *binding = (char *) 0; + struct sockaddr_in *sa; + struct ifreq *ifr = ifc->ifc_req; /* Union maps buffer to correct struct */ + + /* Ensure we have space for two struct ifreqs, fail if not. */ + if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq))) + { + set_errno (EFAULT); + return -1; + } + + /* Set up interface lo0 first */ + strcpy (ifr->ifr_name, "lo0"); + memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr)); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK); + break; + case SIOCGIFBRDADDR: + lip = htonl (INADDR_LOOPBACK); + lnp = cygwin_inet_addr ("255.0.0.0"); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0"); + break; + default: + set_errno (EINVAL); + return -1; + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\" + "CurrentControlSet\\" + "Services\\" + "Tcpip\\" + "Linkage", + 0, KEY_READ, &key) == ERROR_SUCCESS) + { + if (RegQueryValueEx (key, "Bind", + NULL, &type, + NULL, &size) == ERROR_SUCCESS) + { + binding = new char [ size ]; + if (RegQueryValueEx (key, "Bind", + NULL, &type, + (unsigned char *) binding, + &size) != ERROR_SUCCESS) + { + delete [] binding; + binding = (char *) 0; + } + } + RegCloseKey (key); + } + if (binding) + { + char *bp, eth[2]; + char cardkey[256], ipaddress[256], netmask[256]; + + eth[0] = '/'; + eth[1] = '\0'; + for (bp = binding; *bp; bp += strlen(bp) + 1) + { + bp += strlen ("\\Device\\"); + strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\"); + strcat (cardkey, bp); + strcat (cardkey, "\\Parameters\\Tcpip"); + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey, + 0, KEY_READ, &key) != ERROR_SUCCESS) + continue; + if (RegQueryValueEx (key, "IPAddress", + NULL, &type, + (unsigned char *) &ipaddress, + (size = 256, &size)) == ERROR_SUCCESS + && RegQueryValueEx (key, "SubnetMask", + NULL, &type, + (unsigned char *) &netmask, + (size = 256, &size)) == ERROR_SUCCESS) + { + char *ip, *np; + char sub[2]; + char dhcpaddress[256], dhcpnetmask[256]; + + sub[0] = '/'; + sub[1] = '\0'; + if (strncmp (bp, "NdisWan", 7)) + ++*eth; + for (ip = ipaddress, np = netmask; + *ip && *np; + ip += strlen (ip) + 1, np += strlen (np) + 1) + { + if ((caddr_t) ++ifr > ifc->ifc_buf + + ifc->ifc_len + - sizeof (struct ifreq)) + break; + + if (! strncmp(bp, "NdisWan", 7)) + { + strcpy (ifr->ifr_name, "ppp"); + strcat (ifr->ifr_name, bp + 7); + } + else + { + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + } + ++*sub; + if (*sub >= '1') + strcat (ifr->ifr_name, sub); + memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr); + if (cygwin_inet_addr (ip) == 0L + && RegQueryValueEx (key, "DhcpIPAddress", + NULL, &type, + (unsigned char *) &dhcpaddress, + (size = 256, &size)) + == ERROR_SUCCESS + && RegQueryValueEx (key, "DhcpSubnetMask", + NULL, &type, + (unsigned char *) &dhcpnetmask, + (size = 256, &size)) + == ERROR_SUCCESS) + { + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = + cygwin_inet_addr (dhcpaddress); + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (dhcpaddress); + lnp = cygwin_inet_addr (dhcpnetmask); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = + cygwin_inet_addr (dhcpnetmask); + break; + } + } + else + { + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = cygwin_inet_addr (ip); + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (ip); + lnp = cygwin_inet_addr (np); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr (np); + break; + } + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + ++cnt; + } + } + RegCloseKey (key); + } + delete [] binding; + } + + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); + + return 0; } /* Cygwin internal */ /* * Return the flags settings for an interface. - * This is broken at the moment as it doesn't check - * if the interfaces are really up or down, but can - * Windows net interfaces really be down? (Ignore the - * Wan interfaces for now). */ static int get_if_flags (struct ifreq *ifr) { - short flags = IFF_UP | IFF_NOTRAILERS | IFF_RUNNING; + short flags = IFF_NOTRAILERS; struct sockaddr_in *sa = (struct sockaddr_in *) &ifr->ifr_addr; - if (sa->sin_addr.s_addr == INADDR_LOOPBACK) - flags |= IFF_LOOPBACK; - else + if (sa->sin_addr.s_addr == INADDR_ANY) flags |= IFF_BROADCAST; + else if (sa->sin_addr.s_addr == INADDR_LOOPBACK) + flags |= IFF_LOOPBACK | IFF_UP | IFF_RUNNING; + else + flags |= IFF_BROADCAST | IFF_UP | IFF_RUNNING; ifr->ifr_flags = flags; return 0; } @@ -1516,9 +1775,9 @@ fhandler_socket::ioctl (unsigned int cmd return -1; } if (os_being_run == winNT) - res = get_winnt_ifconf (ifc); + res = get_winnt_ifconf (ifc, cmd); else - res = get_win95_ifconf (ifc); + res = get_win95_ifconf (ifc, cmd); break; } case SIOCGIFFLAGS: @@ -1531,6 +1790,60 @@ fhandler_socket::ioctl (unsigned int cmd } res = get_if_flags (ifr); break; + } + case SIOCGIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCGIFADDR: + { + char buf[2048]; + struct ifconf ifc; + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + struct ifreq *ifrp; + + struct ifreq *ifr = (struct ifreq *) p; + if (ifr == 0) + { + debug_printf("ifr == NULL\n"); + set_errno (EINVAL); + return -1; + } + if (os_being_run == winNT) + res = get_winnt_ifconf (&ifc, cmd); + else + res = get_win95_ifconf (&ifc, cmd); + if (res) { + debug_printf("error in get_winXX_ifconf\n"); + break; + } + debug_printf(" name: %s\n", ifr->ifr_name); + for (ifrp = ifc.ifc_req; + (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len; + ++ifrp) + { + debug_printf("testname: %s\n", ifrp->ifr_name); + if (! strcmp(ifrp->ifr_name, ifr->ifr_name)) + { + switch (cmd) { + case SIOCGIFADDR: + ifr->ifr_addr = ifrp->ifr_addr; + break; + case SIOCGIFBRDADDR: + ifr->ifr_broadaddr = ifrp->ifr_broadaddr; + break; + case SIOCGIFNETMASK: + ifr->ifr_netmask = ifrp->ifr_netmask; + break; + } + break; + } + } + if ((caddr_t) ifrp >= ifc.ifc_buf + ifc.ifc_len) + { + set_errno (EINVAL); + return -1; + } + break; } case FIOASYNC: { --------------7201EB56BC7E17190054A4E1--