- improve WsControl error checking
- make WsControl output more closely match Win98's
- document WsControl behavior a bit better
diff --git a/dlls/wsock32/socket.c b/dlls/wsock32/socket.c
index 7a2025f..b61e26d 100644
--- a/dlls/wsock32/socket.c
+++ b/dlls/wsock32/socket.c
@@ -2,6 +2,7 @@
* WSOCK32 specific functions
*
* Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
+ * Copyright (C) 2003 Juan Lang.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -81,22 +82,21 @@
* From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
* Date: 1997/08/17
*
- * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
+ * The WSCNTL_TCPIP_QUERY_INFO option is partially implemented based
* on observing the behaviour of WsControl with an app in
* Windows 98. It is not fully implemented, and there could
* be (are?) errors due to incorrect assumptions made.
*
*
* WsControl returns WSCTL_SUCCESS on success.
- * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
- * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
- *
- * It doesn't seem to generate errors that can be retrieved by
- * WSAGetLastError().
+ * ERROR_LOCK_VIOLATION is returned if the output buffer length
+ * (*pcbResponseInfoLen) is too small. This is an unusual error code, but
+ * it matches Win98's behavior. Other errors come from winerror.h, not from
+ * winsock.h. Again, this is to match Win98 behavior.
*
*/
-DWORD WINAPI WsControl(DWORD protocoll,
+DWORD WINAPI WsControl(DWORD protocol,
DWORD action,
LPVOID pRequestInfo,
LPDWORD pcbRequestInfoLen,
@@ -108,288 +108,400 @@
rather than void */
TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
+ /* validate input parameters. Error codes are from winerror.h, not from
+ * winsock.h. pcbResponseInfoLen is apparently allowed to be NULL for some
+ * commands, since winipcfg.exe fails if we ensure it's non-NULL in every
+ * case.
+ */
+ if (protocol != IPPROTO_TCP) return ERROR_INVALID_PARAMETER;
+ if (!pcommand) return ERROR_INVALID_PARAMETER;
+ if (!pcbRequestInfoLen) return ERROR_INVALID_ACCESS;
+ if (*pcbRequestInfoLen < sizeof(TDIObjectID)) return ERROR_INVALID_ACCESS;
+ if (!pResponseInfo) return ERROR_INVALID_PARAMETER;
+ if (pcommand->toi_type != INFO_TYPE_PROVIDER) return ERROR_INVALID_PARAMETER;
+
TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
- pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
- pcommand->toi_class, pcommand->toi_type );
-
-
+ pcommand->toi_id, pcommand->toi_entity.tei_entity,
+ pcommand->toi_entity.tei_instance,
+ pcommand->toi_class, pcommand->toi_type );
switch (action)
{
- case WSCNTL_TCPIP_QUERY_INFO:
+ case WSCNTL_TCPIP_QUERY_INFO:
+ {
+ if (pcommand->toi_class != INFO_CLASS_GENERIC &&
+ pcommand->toi_class != INFO_CLASS_PROTOCOL)
{
- switch (pcommand->toi_id)
+ ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO",
+ pcommand->toi_class);
+ return ERROR_BAD_ENVIRONMENT;
+ }
+
+ switch (pcommand->toi_id)
+ {
+ /* ENTITY_LIST_ID gets the list of "entity IDs", where an entity
+ may represent an interface, or a datagram service, or address
+ translation, or other fun things. Typically an entity ID represents
+ a class of service, which is further queried for what type it is.
+ Different types will then have more specific queries defined.
+ */
+ case ENTITY_LIST_ID:
{
- /*
- ENTITY_LIST_ID seems to get number of adapters in the system.
- (almost like an index to be used when calling other WsControl options)
- */
- case ENTITY_LIST_ID:
+ TDIEntityID *baseptr = (TDIEntityID *)pResponseInfo;
+ DWORD numInt, i, ifTable, spaceNeeded;
+ PMIB_IFTABLE table;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (pcommand->toi_class != INFO_CLASS_GENERIC)
{
- TDIEntityID *baseptr = pResponseInfo;
- DWORD numInt, i, ipAddrTableSize;
- PMIB_IPADDRTABLE table;
+ FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx",
+ pcommand->toi_class);
+ return (ERROR_BAD_ENVIRONMENT);
+ }
- if (pcommand->toi_class != INFO_CLASS_GENERIC &&
- pcommand->toi_type != INFO_TYPE_PROVIDER)
- {
- FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
- pcommand->toi_class, pcommand->toi_type);
- return (WSAEOPNOTSUPP);
- }
+ GetNumberOfInterfaces(&numInt);
+ spaceNeeded = sizeof(TDIEntityID) * (numInt + 4);
- GetNumberOfInterfaces(&numInt);
+ if (*pcbResponseInfoLen < spaceNeeded)
+ return (ERROR_LOCK_VIOLATION);
- if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
+ ifTable = 0;
+ GetIfTable(NULL, &ifTable, FALSE);
+ table = (PMIB_IFTABLE)calloc(1, ifTable);
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ GetIfTable(table, &ifTable, FALSE);
- /* expect a 1:1 correspondence between interfaces and IP
- addresses, so use the cheaper (less memory allocated)
- GetIpAddrTable rather than GetIfTable */
- ipAddrTableSize = 0;
- GetIpAddrTable(NULL, &ipAddrTableSize, FALSE);
- table = (PMIB_IPADDRTABLE)calloc(1, ipAddrTableSize);
- if (!table) return -1; /* FIXME: better error code */
- GetIpAddrTable(table, &ipAddrTableSize, FALSE);
-
- /* 0 it out first */
- memset(baseptr, 0, sizeof(TDIEntityID)*(table->dwNumEntries*2));
-
- for (i=0; i<table->dwNumEntries; i++)
- {
- /* tei_instance is an network interface identifier.
- I'm not quite sure what the difference is between tei_entity values of
- CL_NL_ENTITY and IF_ENTITY */
- baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++;
- baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++;
- }
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof(TDIEntityID)*(table->dwNumEntries*2);
+ spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
+ if (*pcbResponseInfoLen < spaceNeeded)
+ {
free(table);
-
- break;
+ return (ERROR_LOCK_VIOLATION);
}
+ memset(baseptr, 0, spaceNeeded);
- /* ENTITY_TYPE_ID is used to obtain simple information about a
- network card, such as MAC Address, description, interface type,
- number of network addresses, etc. */
- case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
+ for (i = 0; i < table->dwNumEntries; i++)
{
- if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
+ /* Return IF_GENERIC on every interface, and AT_ENTITY,
+ * CL_NL_ENTITY, CL_TL_ENTITY, and CO_TL_ENTITY on the first
+ * interface. MS returns them only on the loopback
+ * interface, but it doesn't seem to matter.
+ */
+ if (i == 0)
{
- if (pcommand->toi_entity.tei_entity == IF_ENTITY)
- {
- * ((ULONG *)pResponseInfo) = IF_MIB;
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof (ULONG);
-
- }
- else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
- {
- * ((ULONG *)pResponseInfo) = CL_NL_IP;
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof (ULONG);
- }
+ baseptr->tei_entity = CO_TL_ENTITY;
+ baseptr->tei_instance = table->table[i].dwIndex;
+ baseptr++;
+ baseptr->tei_entity = CL_TL_ENTITY;
+ baseptr->tei_instance = table->table[i].dwIndex;
+ baseptr++;
+ baseptr->tei_entity = CL_NL_ENTITY;
+ baseptr->tei_instance = table->table[i].dwIndex;
+ baseptr++;
+ baseptr->tei_entity = AT_ENTITY;
+ baseptr->tei_instance = table->table[i].dwIndex;
+ baseptr++;
}
- else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
- pcommand->toi_type == INFO_TYPE_PROVIDER)
- {
- if (pcommand->toi_entity.tei_entity == IF_ENTITY)
- {
- MIB_IFROW row;
- DWORD index = pcommand->toi_entity.tei_instance, ret;
- DWORD size = sizeof(row) - sizeof(row.wszName) -
- sizeof(row.bDescr);
-
- if (*pcbResponseInfoLen < size)
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
- row.dwIndex = index;
- ret = GetIfEntry(&row);
- if (ret != NO_ERROR)
- {
- ERR ("Error retrieving data for interface index %lu\n", index);
- return -1; /* FIXME: better error code */
- }
- size = sizeof(row) - sizeof(row.wszName) -
- sizeof(row.bDescr) + row.dwDescrLen;
- if (*pcbResponseInfoLen < size)
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
- memcpy(pResponseInfo, &row.dwIndex, size);
- *pcbResponseInfoLen = size;
- }
- else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
- {
- /* This case is used to obtain general statistics about the
- network */
-
- if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
- GetIpStatistics((PMIB_IPSTATS)pResponseInfo);
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
- }
- }
- else
- {
- FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
- pcommand->toi_class, pcommand->toi_type);
-
- return (WSAEOPNOTSUPP);
- }
-
- break;
+ baseptr->tei_entity = IF_GENERIC;
+ baseptr->tei_instance = table->table[i].dwIndex;
+ baseptr++;
}
+ *pcbResponseInfoLen = spaceNeeded;
+ free(table);
- /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
- particular network adapter */
- case IP_MIB_ADDRTABLE_ENTRY_ID:
- {
- DWORD index = pcommand->toi_entity.tei_instance;
- PMIB_IPADDRROW baseIPInfo = (PMIB_IPADDRROW) pResponseInfo;
- PMIB_IPADDRTABLE table;
- DWORD tableSize, i;
-
- if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
-
- /* overkill, get entire table, because there isn't an
- exported function that gets just one entry, and don't
- necessarily want our own private export. */
- tableSize = 0;
- GetIpAddrTable(NULL, &tableSize, FALSE);
- table = (PMIB_IPADDRTABLE)calloc(1, tableSize);
- if (!table) return -1; /* FIXME: better error code */
- GetIpAddrTable(table, &tableSize, FALSE);
- for (i = 0; i < table->dwNumEntries; i++)
- {
- if (table->table[i].dwIndex == index)
- {
- memcpy(baseIPInfo, &table->table[i],
- sizeof(MIB_IPADDRROW));
- break;
- }
- }
- free(table);
-
- /************************************************************************/
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
- 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 */
- {
- DWORD routeTableSize, numRoutes, ndx;
- PMIB_IPFORWARDTABLE table;
- IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo;
-
- GetIpForwardTable(NULL, &routeTableSize, FALSE);
- numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE), 0)
- / sizeof(MIB_IPFORWARDROW) + 1;
- if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
- table = (PMIB_IPFORWARDTABLE)calloc(1, routeTableSize);
- if (!table) return -1; /* FIXME: better return value */
- GetIpForwardTable(table, &routeTableSize, FALSE);
-
- memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
- for (ndx = 0; ndx < table->dwNumEntries; ndx++)
- {
- winRouteTable->ire_addr =
- table->table[ndx].dwForwardDest;
- winRouteTable->ire_index =
- table->table[ndx].dwForwardIfIndex;
- winRouteTable->ire_metric =
- table->table[ndx].dwForwardMetric1;
- /* winRouteTable->ire_option4 =
- winRouteTable->ire_option5 =
- winRouteTable->ire_option6 = */
- winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop;
- /* winRouteTable->ire_option8 =
- winRouteTable->ire_option9 =
- winRouteTable->ire_option10 = */
- winRouteTable->ire_mask = table->table[ndx].dwForwardMask;
- /* winRouteTable->ire_option12 = */
- winRouteTable++;
- }
-
- /* calculate the length of the data in the output buffer */
- *pcbResponseInfoLen = sizeof(IPRouteEntry) *
- table->dwNumEntries;
-
- free(table);
- break;
- }
-
-
- default:
- {
- FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx, toi_type=0x%lx\n",
- pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
- pcommand->toi_class, pcommand->toi_type);
-
- return (WSAEOPNOTSUPP);
- }
+ break;
}
+ /* Returns MIB-II statistics for an interface */
+ case ENTITY_TYPE_ID:
+ switch (pcommand->toi_entity.tei_entity)
+ {
+ case IF_GENERIC:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = IF_MIB;
+ *pcbResponseInfoLen = sizeof(ULONG);
+ }
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
+ {
+ MIB_IFROW row;
+ DWORD index = pcommand->toi_entity.tei_instance, ret;
+ DWORD size = sizeof(row) - sizeof(row.wszName) -
+ sizeof(row.bDescr);
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < size)
+ return (ERROR_LOCK_VIOLATION);
+ row.dwIndex = index;
+ ret = GetIfEntry(&row);
+ if (ret != NO_ERROR)
+ {
+ ERR ("Error retrieving data for interface index %lu\n",
+ index);
+ return ret;
+ }
+ size = sizeof(row) - sizeof(row.wszName) -
+ sizeof(row.bDescr) + row.dwDescrLen;
+ if (*pcbResponseInfoLen < size)
+ return (ERROR_LOCK_VIOLATION);
+ memcpy(pResponseInfo, &row.dwIndex, size);
+ *pcbResponseInfoLen = size;
+ }
+ break;
+
+ /* Returns address-translation related data. In our case, this is
+ * ARP.
+ * FIXME: Win98 seems to assume ARP will always be on interface
+ * index 1, so arp.exe fails when this isn't the case.
+ */
+ case AT_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = AT_ARP;
+ *pcbResponseInfoLen = sizeof(ULONG);
+ }
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
+ {
+ PMIB_IPNETTABLE table;
+ DWORD size;
+ PULONG output = (PULONG)pResponseInfo;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(ULONG) * 2)
+ return (ERROR_LOCK_VIOLATION);
+ GetIpNetTable(NULL, &size, FALSE);
+ table = (PMIB_IPNETTABLE)calloc(1, size);
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ GetIpNetTable(table, &size, FALSE);
+ /* FIXME: I don't understand the meaning of the ARP output
+ * very well, but it seems to indicate how many ARP entries
+ * exist. I don't know whether this should reflect the
+ * number per interface, as I'm only testing with a single
+ * interface. So, I lie and say all ARP entries exist on
+ * a single interface--the first one that appears in the
+ * ARP table.
+ */
+ *(output++) = table->dwNumEntries;
+ *output = table->table[0].dwIndex;
+ free(table);
+ *pcbResponseInfoLen = sizeof(ULONG) * 2;
+ }
+ break;
+
+ /* Returns connectionless network layer statistics--in our case,
+ * this is IP.
+ */
+ case CL_NL_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = CL_NL_IP;
+ *pcbResponseInfoLen = sizeof(ULONG);
+ }
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
+ return ERROR_LOCK_VIOLATION;
+ GetIpStatistics((PMIB_IPSTATS)pResponseInfo);
+
+ *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
+ }
+ break;
+
+ /* Returns connectionless transport layer statistics--in our case,
+ * this is UDP.
+ */
+ case CL_TL_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = CL_TL_UDP;
+ *pcbResponseInfoLen = sizeof(ULONG);
+ }
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS))
+ return ERROR_LOCK_VIOLATION;
+ GetUdpStatistics((PMIB_UDPSTATS)pResponseInfo);
+ *pcbResponseInfoLen = sizeof(MIB_UDPSTATS);
+ }
+ break;
+
+ /* Returns connection-oriented transport layer statistics--in our
+ * case, this is TCP.
+ */
+ case CO_TL_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = CO_TL_TCP;
+ *pcbResponseInfoLen = sizeof(ULONG);
+ }
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
+ {
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS))
+ return ERROR_LOCK_VIOLATION;
+ GetTcpStatistics((PMIB_TCPSTATS)pResponseInfo);
+ *pcbResponseInfoLen = sizeof(MIB_TCPSTATS);
+ }
+ break;
+
+ default:
+ ERR("Unknown entity %ld for ENTITY_TYPE_ID query",
+ pcommand->toi_entity.tei_entity);
+ }
break;
+
+ /* This call returns the IP address, subnet mask, and broadcast
+ * address for an interface. If there are multiple IP addresses for
+ * the interface with the given index, returns the "first" one.
+ */
+ case IP_MIB_ADDRTABLE_ENTRY_ID:
+ {
+ DWORD index = pcommand->toi_entity.tei_instance;
+ PMIB_IPADDRROW baseIPInfo = (PMIB_IPADDRROW) pResponseInfo;
+ PMIB_IPADDRTABLE table;
+ DWORD tableSize, i;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
+ return (ERROR_LOCK_VIOLATION);
+
+ /* get entire table, because there isn't an exported function that
+ gets just one entry. */
+ tableSize = 0;
+ GetIpAddrTable(NULL, &tableSize, FALSE);
+ table = (PMIB_IPADDRTABLE)calloc(1, tableSize);
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ GetIpAddrTable(table, &tableSize, FALSE);
+ for (i = 0; i < table->dwNumEntries; i++)
+ {
+ if (table->table[i].dwIndex == index)
+ {
+ memcpy(baseIPInfo, &table->table[i],
+ sizeof(MIB_IPADDRROW));
+ break;
+ }
+ }
+ free(table);
+
+ *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
+ 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 */
+ {
+ DWORD routeTableSize, numRoutes, ndx;
+ PMIB_IPFORWARDTABLE table;
+ IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ GetIpForwardTable(NULL, &routeTableSize, FALSE);
+ numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE), 0)
+ / sizeof(MIB_IPFORWARDROW) + 1;
+ if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
+ return (ERROR_LOCK_VIOLATION);
+ table = (PMIB_IPFORWARDTABLE)calloc(1, routeTableSize);
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ GetIpForwardTable(table, &routeTableSize, FALSE);
+
+ memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
+ for (ndx = 0; ndx < table->dwNumEntries; ndx++)
+ {
+ winRouteTable->ire_addr = table->table[ndx].dwForwardDest;
+ winRouteTable->ire_index = table->table[ndx].dwForwardIfIndex;
+ winRouteTable->ire_metric =
+ table->table[ndx].dwForwardMetric1;
+ /* winRouteTable->ire_option4 =
+ winRouteTable->ire_option5 =
+ winRouteTable->ire_option6 = */
+ winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop;
+ /* winRouteTable->ire_option8 =
+ winRouteTable->ire_option9 =
+ winRouteTable->ire_option10 = */
+ winRouteTable->ire_mask = table->table[ndx].dwForwardMask;
+ /* winRouteTable->ire_option12 = */
+ winRouteTable++;
+ }
+
+ /* calculate the length of the data in the output buffer */
+ *pcbResponseInfoLen = sizeof(IPRouteEntry) *
+ table->dwNumEntries;
+
+ free(table);
+ break;
+ }
+
+
+ default:
+ {
+ FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
+ pcommand->toi_id, pcommand->toi_entity.tei_entity,
+ pcommand->toi_entity.tei_instance, pcommand->toi_class);
+
+ return (ERROR_BAD_ENVIRONMENT);
+ }
}
- case WSCNTL_TCPIP_ICMP_ECHO:
- {
- unsigned int addr = *(unsigned int*)pRequestInfo;
- #if 0
- int timeout= *(unsigned int*)(inbuf+4);
- short x1 = *(unsigned short*)(inbuf+8);
- short sendbufsize = *(unsigned short*)(inbuf+10);
- char x2 = *(unsigned char*)(inbuf+12);
- char ttl = *(unsigned char*)(inbuf+13);
- char service = *(unsigned char*)(inbuf+14);
- char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
- #endif
-
- FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
- break;
- }
-
- default:
- {
- FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
- protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
-
- return (WSAEOPNOTSUPP);
- }
+ break;
}
+ case WSCNTL_TCPIP_ICMP_ECHO:
+ {
+ unsigned int addr = *(unsigned int*)pRequestInfo;
+ #if 0
+ int timeout= *(unsigned int*)(inbuf+4);
+ short x1 = *(unsigned short*)(inbuf+8);
+ short sendbufsize = *(unsigned short*)(inbuf+10);
+ char x2 = *(unsigned char*)(inbuf+12);
+ char ttl = *(unsigned char*)(inbuf+13);
+ char service = *(unsigned char*)(inbuf+14);
+ char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
+ #endif
+
+ FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
+ break;
+ }
+
+ default:
+ FIXME("Protocol Not Supported -> protocol=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
+ protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
+
+ return (WSAEOPNOTSUPP);
+
+ }
return (WSCTL_SUCCESS);
}
diff --git a/dlls/wsock32/wscontrol.h b/dlls/wsock32/wscontrol.h
index 1cca5b1..576a433 100644
--- a/dlls/wsock32/wscontrol.h
+++ b/dlls/wsock32/wscontrol.h
@@ -6,9 +6,12 @@
*
* The functionality of WsControl was created by observing its behaviour
* in Windows 98, so there are likely to be bugs with the assumptions
- * that were made.
+ * that were made. A significant amount of help came from
+ * http://tangentsoft.net/wskfaq/articles/wscontrol.html , especially the
+ * trace by Thomas Divine (www.pcausa.net).
*
* Copyright 2000 James Hatheway
+ * Copyright 2003 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -28,8 +31,6 @@
#ifndef WSCONTROL_H_INCLUDED
#define WSCONTROL_H_INCLUDED
-typedef unsigned char uchar; /* This doesn't seem to be in any standard headers */
-
#define WSCTL_SUCCESS 0
/*
@@ -57,44 +58,6 @@
unsigned long toi_id;
} TDIObjectID;
-typedef struct IPSNMPInfo
-{
- unsigned long ipsi_forwarding;
- unsigned long ipsi_defaultttl;
- unsigned long ipsi_inreceives;
- unsigned long ipsi_inhdrerrors;
- unsigned long ipsi_inaddrerrors;
- unsigned long ipsi_forwdatagrams;
- unsigned long ipsi_inunknownprotos;
- unsigned long ipsi_indiscards;
- unsigned long ipsi_indelivers;
- unsigned long ipsi_outrequests;
- unsigned long ipsi_routingdiscards;
- unsigned long ipsi_outdiscards;
- unsigned long ipsi_outnoroutes;
- unsigned long ipsi_reasmtimeout;
- unsigned long ipsi_reasmreqds;
- unsigned long ipsi_reasmoks;
- unsigned long ipsi_reasmfails;
- unsigned long ipsi_fragoks;
- unsigned long ipsi_fragfails;
- unsigned long ipsi_fragcreates;
- unsigned long ipsi_numif;
- unsigned long ipsi_numaddr;
- unsigned long ipsi_numroutes;
-} IPSNMPInfo;
-
-typedef struct IPAddrEntry
-{
- unsigned long iae_addr;
- unsigned long iae_index;
- unsigned long iae_mask;
- unsigned long iae_bcastaddr;
- unsigned long iae_reasmsize;
- ushort iae_context;
- ushort iae_pad;
-} IPAddrEntry;
-
#ifdef if_type
#undef if_type
#endif
@@ -114,7 +77,7 @@
unsigned long if_mtu;
unsigned long if_speed;
unsigned long if_physaddrlen;
- uchar if_physaddr[MAX_PHYSADDR_SIZE];
+ unsigned char if_physaddr[MAX_PHYSADDR_SIZE];
unsigned long if_adminstatus;
unsigned long if_operstatus;
unsigned long if_lastchange;
@@ -131,7 +94,7 @@
unsigned long if_outerrors;
unsigned long if_outqlen;
unsigned long if_descrlen;
- uchar if_descr[1];
+ unsigned char if_descr[1];
} IFEntry;
@@ -153,34 +116,58 @@
} IPRouteEntry;
-/* Not sure what EXACTLY most of this stuff does.
- WsControl was implemented mainly by observing
- its behaviour in Win98 ************************/
-#define INFO_CLASS_GENERIC 0x100
-#define INFO_CLASS_PROTOCOL 0x200
-#define INFO_TYPE_PROVIDER 0x100
-#define ENTITY_LIST_ID 0
-#define CL_NL_ENTITY 0x301
-#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 */
-/************************************************/
+/* Constants for use in the toi_id field */
+#define ENTITY_LIST_ID 0 /* to get the list of entity IDs */
+#define ENTITY_TYPE_ID 1 /* it's an interface; what type of interface is it? */
+#define IP_MIB_ROUTETABLE_ENTRY_ID 0x101 /* not real name */
+#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102
-/* Valid values to get back from entity type ID query */
-#define CO_TL_NBF 0x400 /* Entity implements NBF prot. */
-#define CO_TL_SPX 0x402 /* Entity implements SPX prot. */
-#define CO_TL_TCP 0x404 /* Entity implements TCP prot. */
-#define CO_TL_SPP 0x406 /* Entity implements SPP prot. */
-#define CL_TL_NBF 0x401 /* CL NBF protocol */
-#define CL_TL_UDP 0x403 /* Entity implements UDP */
-#define ER_ICMP 0x380 /* The ICMP protocol */
-#define CL_NL_IPX 0x301 /* Entity implements IPX */
-#define CL_NL_IP 0x303 /* Entity implements IP */
-#define AT_ARP 0x280 /* Entity implements ARP */
-#define AT_NULL 0x282 /* Entity does no address */
-#define IF_GENERIC 0x200 /* Generic interface */
-#define IF_MIB 0x202 /* Supports MIB-2 interface */
+/* Constants for use in the toi_class field */
+#define INFO_CLASS_GENERIC 0x100
+#define INFO_CLASS_PROTOCOL 0x200
+/* Constants for use in the toi_type field */
+#define INFO_TYPE_PROVIDER 0x100
+
+/* Interface types. The first one can be returned in the entity ID list--it's
+ * an interface, and it can be further queried for what type of interface it is.
+ */
+#define IF_GENERIC 0x200 /* generic interface */
+#define IF_MIB 0x202 /* supports MIB-2 interface */
+
+/* address translation types. The first can be turned in the entity ID list--
+ * it supports address translation of some type, and it can be further queried
+ * for what type of address translation it supports (I think).
+ */
+#define AT_ENTITY 0x280
+#define AT_ARP 0x280
+#define AT_NULL 0x282 /* doesn't do address translation after all (liar) */
+
+/* network layer service providers. The first one can be returned in the
+ * entity list ID--it supports a network layer (datagram) service, and it can
+ * be further queried for what type of network layer service it provides.
+ */
+#define CL_NL_ENTITY 0x301
+#define CL_NL_IPX 0x301 /* implements IPX--probably won't see this, since
+ * we're querying the TCP protocol */
+#define CL_NL_IP 0x303 /* implements IP */
+
+/* echo request/response types. The first can be returned in the entity ID
+ * list--it can be further queried for what type of echo it supports (I think).
+ */
+#define ER_ENTITY 0x380
+#define ER_ICMP 0x380
+
+/* connection-oriented transport layer protocols--you know the drill by now */
+#define CO_TL_ENTITY 0x400
+#define CO_TL_NBF 0x400
+#define CO_TL_SPX 0x402
+#define CO_TL_TCP 0x404
+#define CO_TL_SPP 0x406
+
+/* connectionless transport layer protocols--you know the drill by now */
+#define CL_TL_ENTITY 0x401
+#define CL_TL_NBF 0x401
+#define CL_TL_UDP 0x403
#endif /* WSCONTROL_H_INCLUDED */