wsock32: WsControl

Michael Stefaniuc mstefani at redhat.de
Tue Feb 27 12:15:12 CST 2001


Hello,

this patch implements the WsControl command with the id 0x101.
WsControl is an undocumented Win9x function and returns the IP routing
table. The patch works with route.exe and should also work with
winipcfg.exe and ipconfig.exe (It worked with both progams with a week
old cvs extract, but not with an actual snapshot. Ok both programs don't
work anymore even without my patch, they are now crashing before calling
the WsControl function).
Like the whole WsControl function this patch works only with Linux.
FreeBSD dosn't have the /proc/net/{dev,route} or corresponding files and
I didn't had the time to look for an implementation for that OS. And
regarding Solaris ... I don't have a Solaris mashine handy.

It's my first wine patch so please take a closer look at it before
applying it.


Log:
	Implements WsControl command with id 0x101


bye
	michael
-- 
Michael Stefaniuc               Tel.: +49-711-96437-199
System Administration           Fax.: +49-711-96437-111
Red Hat GmbH                    Email: mstefani at redhat.de
Hauptstaetterstr. 58            http://www.redhat.de/
D-70178 Stuttgart
-------------- next part --------------
Index: socket.c
===================================================================
RCS file: /home/wine/wine/dlls/wsock32/socket.c,v
retrieving revision 1.8
diff -u -r1.8 socket.c
--- socket.c	2001/01/26 20:43:45	1.8
+++ socket.c	2001/02/27 18:11:50
@@ -40,6 +40,7 @@
 #ifdef HAVE_NET_IF_H
 # include <net/if.h>
 #endif
+#include <errno.h>
 
 
 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
@@ -116,7 +117,7 @@
                   return (WSAEOPNOTSUPP); 
                }
            
-               numInt = WSCNTL_GetInterfaceCount(); 
+               numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES); 
                if (numInt < 0)
                {
                   ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
@@ -263,7 +264,7 @@
                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY) 
                   {
                      IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
-                     int numInt;
+                     int numInt, numRoutes;
                      
                      /* This case is used to obtain general statistics about the 
                         network */
@@ -278,16 +279,23 @@
                         memset(infoStruc, 0, sizeof(IPSNMPInfo));
             
                         /* Get the number of interfaces */
-                        numInt = WSCNTL_GetInterfaceCount(); 
+                        numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES); 
                         if (numInt < 0)
                         {
                            ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
                            return (-1); 
                         }
+                        /* Get the number of routes */
+                        numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES); 
+                        if (numRoutes < 0)
+                        {
+                           ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
+                           return (-1); 
+                        }
 
                         infoStruc->ipsi_numif           = numInt; /* # of interfaces */
                         infoStruc->ipsi_numaddr         = numInt; /* # of addresses */
-                        infoStruc->ipsi_numroutes       = numInt; /* # of routes ~ FIXME - Is this right? */
+                        infoStruc->ipsi_numroutes       = numRoutes; /* # of routes */
 
                         /* FIXME: How should the below be properly calculated? ******************/
                         infoStruc->ipsi_forwarding      = 0x0;
@@ -334,7 +342,7 @@
             case IP_MIB_ADDRTABLE_ENTRY_ID: 
             {
                IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
-               char ifName[512];
+               char ifName[IFNAMSIZ+1];
                struct ifreq ifInfo;
                SOCKET sock;
 
@@ -424,10 +432,82 @@
                break;
             }
 
-            case 0x101:
-                FIXME ("Command ID Unknown but used by winipcfg.exe\n");
-                break;
 
+	    /* This call returns the routing table.
+	     * No official documentation found, even the name of the command is unknown.
+	     * Work is based on
+	     * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
+	     * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
+	     * pcommand->toi_entity.tei_instance seems to be the interface number
+	     * but route.exe outputs only the information for the last interface
+	     * if only the routes for the pcommand->toi_entity.tei_instance
+	     * interface are returned. */
+	    case IP_MIB_ROUTETABLE_ENTRY_ID:	/* FIXME: not real name. Value is 0x101 */
+	    {
+		int numRoutes, foundRoutes;
+		wscntl_routeentry *routeTable, *routePtr;	/* route table */
+	        
+                IPRouteEntry *winRouteTable  = (IPRouteEntry *) pResponseInfo;
+
+		/* Get the number of routes */
+		numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES); 
+		if (numRoutes < 0)
+		{
+		    ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
+		    return (-1); 
+		}
+
+		if (*pcbResponseInfoLen < (sizeof(IPRouteEntry) * numRoutes))
+		{
+		    return (STATUS_BUFFER_TOO_SMALL); 
+		}
+		
+		/* malloc space for the routeTable */
+		routeTable = (wscntl_routeentry *) malloc(sizeof(wscntl_routeentry) * numRoutes);
+		if (!routeTable)
+	       	{
+		    ERR ("couldn't malloc space for routeTable!\n");
+		}
+
+		/* get the route table */
+		foundRoutes = WSCNTL_GetRouteTable(numRoutes, routeTable);
+		if (foundRoutes < 0)
+		{
+		    ERR ("Unable to open /proc filesystem to parse the route entrys!\n");
+		    free(routeTable);
+		    return -1;
+		}
+		routePtr = routeTable;
+		    
+                /* first 0 out the output buffer */
+                memset(winRouteTable, 0, *pcbResponseInfoLen);
+               
+		/* calculate the length of the data in the output buffer */
+                *pcbResponseInfoLen = sizeof(IPRouteEntry) * foundRoutes;
+		
+		for ( ; foundRoutes > 0; foundRoutes--)
+		{
+		    winRouteTable->ire_addr = routePtr->wre_dest;
+		    winRouteTable->ire_index = routePtr->wre_intf;
+		    winRouteTable->ire_metric = routePtr->wre_metric;
+		    /* winRouteTable->ire_option4 =
+		    winRouteTable->ire_option5 =
+		    winRouteTable->ire_option6 = */
+		    winRouteTable->ire_gw = routePtr->wre_gw;
+		    /* winRouteTable->ire_option8 =
+		    winRouteTable->ire_option9 =
+		    winRouteTable->ire_option10 = */
+		    winRouteTable->ire_mask = routePtr->wre_mask;
+		    /* winRouteTable->ire_option12 = */
+
+		    winRouteTable++;
+		    routePtr++;
+		}
+						    
+		free(routeTable);
+                break;
+	    }
+	    
 
             default: 
             {
@@ -476,35 +556,71 @@
 
 /* 
   Helper function for WsControl - Get count of the number of interfaces
-  by parsing /proc filesystem.
+  or routes by parsing /proc filesystem.
 */
-int WSCNTL_GetInterfaceCount(void)
+int WSCNTL_GetEntryCount(const int entrytype)
 {
-   FILE *procfs;
-   char buf[512];  /* Size doesn't matter, something big */
-   int  intcnt=0;
+   char *filename;
+   int 	fd;
+   char buf[512];  /* Size optimized for a typical workstation */
+   char	*ptr;
+   int  count;
+   int	chrread;
  
  
-   /* Open /proc filesystem file for network devices */ 
-   procfs = fopen(PROCFS_NETDEV_FILE, "r");
-   if (!procfs) 
-   {
-      /* If we can't open the file, return an error */
-      return (-1);
-   }
-   
-   /* Omit first two lines, they are only headers */
-   fgets(buf, sizeof buf, procfs);	
-   fgets(buf, sizeof buf, procfs);
-
-   while (fgets(buf, sizeof buf, procfs)) 
+   switch (entrytype)
    {
-      /* Each line in the file represents a network interface */
-      intcnt++;
+       case WSCNTL_COUNT_INTERFACES:
+       {
+	   filename = PROCFS_NETDEV_FILE;
+	   count = -2;	/* two haeder lines */
+	   break;
+       };
+
+       case WSCNTL_COUNT_ROUTES:
+       {
+	   filename = PROCFS_ROUTE_FILE;
+	   count = -1;	/* one haeder line */
+	   break;
+       };
+
+       default:
+       {
+	   return -1;
+       };
+   }
+
+   /* open /proc filesystem file */
+   fd = open(filename, O_RDONLY);
+   if (fd < 0) {
+       return -1;
+   }
+
+   /* read the file and count the EOL's */
+   while ((chrread = read(fd, buf, sizeof(buf))) != 0) 
+   {
+       ptr = buf;
+       if (chrread < 0) 
+       {
+	   if (errno == EINTR) 
+	   {
+	       continue;	/* read interupted by a signal, try to read again */
+	   }
+	   else
+	   {
+	       close(fd);
+	       return -1;
+	   }
+       }
+       while ((ptr = memchr(ptr, '\n', chrread - (int) (ptr -  buf))) > 0)
+       {
+	   count++;
+	   ptr++;
+       }
    }
 
-   fclose(procfs);
-   return(intcnt);
+   close(fd);
+   return count;
 }
 
 
@@ -708,6 +824,112 @@
 
    fclose(procfs);
    return(TRUE);
+}
+
+
+/* Parse the procfs route file and put the datas into routeTable.
+ * Return value is the number of found routes */
+int WSCNTL_GetRouteTable(int numRoutes, wscntl_routeentry *routeTable)
+{
+    int nrIntf;		/* total number of interfaces */
+    char buf[256];	/* temporary buffer */
+    char *ptr;		/* pointer to temporary buffer */
+    FILE *file;		/* file handle for procfs route file */
+    int foundRoutes = 0;	/* number of found routes */
+    typedef struct interface_t {
+	char intfName[IFNAMSIZ+1];	/* the name of the interface */
+	int intfNameLen;	/* length of interface name */
+    } interface_t;
+    interface_t *interface;
+    int intfNr;		/* the interface number */
+
+    wscntl_routeentry *routePtr = routeTable;
+
+    /* get the number of interfaces */
+    nrIntf = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
+    if (nrIntf < 0)
+    {
+	ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
+	return (-1);
+    }
+
+    /* malloc space for the interface struct array */
+    interface = (interface_t *) malloc(sizeof(interface_t) * nrIntf);
+    if (!routeTable)
+    {
+	ERR ("couldn't malloc space for interface!\n");
+    }
+
+    for (intfNr = 0; intfNr < nrIntf; intfNr++) {
+	if (WSCNTL_GetInterfaceName(intfNr, interface[intfNr].intfName) < 0)
+	{
+	    ERR ("Unable to open /proc filesystem to determine the name of network interfaces!\n");
+	    free(interface);
+	    return (-1);
+	}
+	interface[intfNr].intfNameLen = strlen(interface[intfNr].intfName);
+    }
+
+    /* Open /proc filesystem file for routes */ 
+    file = fopen(PROCFS_ROUTE_FILE, "r");
+    if (!file) 
+    {
+       	/* If we can't open the file, return an error */
+	free(interface);
+	return (-1);
+    }
+    
+    /* skip the header line */
+    fgets(buf, sizeof(buf), file);
+
+    /* parse the rest of the file and put the matching entrys into routeTable.
+       Format of procfs route entry:
+       Iface Destination Gateway Flags RefCnt Use Metric Mask  MTU Window IRTT
+       lo 0000007F 00000000 0001 0 0 0 000000FF 0 0 0
+    */
+    while (fgets(buf, sizeof(buf), file)) {
+	intfNr = 0;
+	/* find the interface of the route */
+	while ((strncmp(buf, interface[intfNr].intfName, interface[intfNr].intfNameLen) != 0) 
+		&& (intfNr < nrIntf))
+	{
+	    intfNr++;
+	}
+	if (intfNr < nrIntf) {
+	    foundRoutes++;
+	    if (foundRoutes > numRoutes) {
+		/* output buffer is to small */
+		ERR("buffer to small to fit all routes found into it!\n");
+		free(interface);
+		fclose(file);
+		return -1;
+	    }
+	    ptr = buf;
+	    ptr += interface[intfNr].intfNameLen;
+	    routePtr->wre_intf = intfNr;
+	    routePtr->wre_dest = strtoul(ptr, &ptr, 16);	/* destination */
+	    routePtr->wre_gw = strtoul(ptr, &ptr, 16);	/* gateway */
+	    strtoul(ptr, &ptr, 16);	/* Flags; unused */
+	    strtoul(ptr, &ptr, 16);	/* RefCnt; unused */
+	    strtoul(ptr, &ptr, 16);	/* Use; unused */
+	    routePtr->wre_metric = strtoul(ptr, &ptr, 16);	/* metric */
+	    routePtr->wre_mask = strtoul(ptr, &ptr, 16);	/* mask */
+	    /* strtoul(ptr, &ptr, 16);	MTU; unused */
+	    /* strtoul(ptr, &ptr, 16);	Window; unused */
+	    /* strtoul(ptr, &ptr, 16);	IRTT; unused */
+
+	    routePtr++;
+	}
+	else
+	{
+	    /* this should never happen */
+	    WARN("Skipping route with unknown interface\n");
+	}
+    }
+
+    free(interface);
+    fclose(file);
+    return foundRoutes;
 }
 
 
Index: wscontrol.h
===================================================================
RCS file: /home/wine/wine/dlls/wsock32/wscontrol.h,v
retrieving revision 1.2
diff -u -r1.2 wscontrol.h
--- wscontrol.h	2000/07/25 17:45:50	1.2
+++ wscontrol.h	2001/02/27 18:11:50
@@ -18,12 +18,27 @@
 #define PROCFS_NETDEV_FILE   "/proc/net/dev" /* Points to the file in the /proc fs 
                                                 that lists the network devices.
                                                 Do we need an #ifdef LINUX for this? */
+#define PROCFS_ROUTE_FILE    "/proc/net/route" /* Points to the file in the /proc fs
+						  that contains the routing table */
+#define WSCNTL_COUNT_INTERFACES	1
+#define WSCNTL_COUNT_ROUTES	2
 
+/* struct contains a routing table entry */
+typedef struct wscntl_routeentry
+{
+    unsigned long wre_intf;
+    unsigned long wre_dest;
+    unsigned long wre_gw;
+    unsigned long wre_mask;
+    unsigned long wre_metric;
+} wscntl_routeentry;
+
 /* WsControl Helper Functions */
-int WSCNTL_GetInterfaceCount(void); /* Obtains the number of network interfaces */
+int WSCNTL_GetEntryCount(const int); /* Obtains the number of network interfaces/routes */
 int WSCNTL_GetInterfaceName(int, char *); /* Obtains the name of an interface */
-int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes); /* Obtains bytes
-                                                                         recv'd/trans by interface */
+int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes,
+       	unsigned long *recvBytes); /* Obtains bytes recv'd/trans by interface */
+int WSCNTL_GetRouteTable(int numRoutes, wscntl_routeentry *routeTable); /* get the routing for the interface intf */
 
 /*
  *      TCP/IP action codes.
@@ -119,6 +134,24 @@
 } IFEntry;
 
 
+/* FIXME: real name and definition of this struct that contains 
+ * an IP route table entry is unknown */
+typedef struct IPRouteEntry {
+   unsigned long ire_addr;
+   unsigned long ire_index;  //matches if_index in IFEntry and iae_index in IPAddrEntry
+   unsigned long ire_metric;
+   unsigned long ire_option4;
+   unsigned long ire_option5;
+   unsigned long ire_option6;
+   unsigned long ire_gw;
+   unsigned long ire_option8;
+   unsigned long ire_option9;
+   unsigned long ire_option10;
+   unsigned long ire_mask;
+   unsigned long ire_option12;
+} IPRouteEntry;
+
+
 /* Not sure what EXACTLY most of this stuff does.
    WsControl was implemented mainly by observing
    its behaviour in Win98 ************************/
@@ -130,6 +163,7 @@
 #define	IF_ENTITY                  0x200
 #define	ENTITY_TYPE_ID             1
 #define	IP_MIB_ADDRTABLE_ENTRY_ID  0x102
+#define	IP_MIB_ROUTETABLE_ENTRY_ID 0x101	/* FIXME: not real name */
 /************************************************/
 
 /* Valid values to get back from entity type ID query */


More information about the wine-patches mailing list