- improve WsControl error checking

- make WsControl output more closely match Win98's
- document WsControl behavior a bit better
This commit is contained in:
Juan Lang 2003-08-29 22:14:28 +00:00 committed by Alexandre Julliard
parent ec42ea4dfb
commit c24fc00f25
2 changed files with 430 additions and 331 deletions

View file

@ -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 @@ INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *o
* 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 @@ DWORD WINAPI WsControl(DWORD protocoll,
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);
}

View file

@ -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 @@ typedef struct TDIObjectID
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 @@ typedef struct IFEntry
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 @@ typedef struct IFEntry
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 @@ typedef struct IPRouteEntry {
} 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 */