- 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 * WSOCK32 specific functions
* *
* Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka. * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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> * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
* Date: 1997/08/17 * 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 * on observing the behaviour of WsControl with an app in
* Windows 98. It is not fully implemented, and there could * Windows 98. It is not fully implemented, and there could
* be (are?) errors due to incorrect assumptions made. * be (are?) errors due to incorrect assumptions made.
* *
* *
* WsControl returns WSCTL_SUCCESS on success. * WsControl returns WSCTL_SUCCESS on success.
* STATUS_BUFFER_TOO_SMALL is returned if the output buffer length * ERROR_LOCK_VIOLATION is returned if the output buffer length
* (*pcbResponseInfoLen) is too small, otherwise errors return -1. * (*pcbResponseInfoLen) is too small. This is an unusual error code, but
* * it matches Win98's behavior. Other errors come from winerror.h, not from
* It doesn't seem to generate errors that can be retrieved by * winsock.h. Again, this is to match Win98 behavior.
* WSAGetLastError().
* *
*/ */
DWORD WINAPI WsControl(DWORD protocoll, DWORD WINAPI WsControl(DWORD protocol,
DWORD action, DWORD action,
LPVOID pRequestInfo, LPVOID pRequestInfo,
LPDWORD pcbRequestInfoLen, LPDWORD pcbRequestInfoLen,
@ -108,154 +108,273 @@ DWORD WINAPI WsControl(DWORD protocoll,
rather than void */ rather than void */
TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo; 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", 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_id, pcommand->toi_entity.tei_entity,
pcommand->toi_entity.tei_instance,
pcommand->toi_class, pcommand->toi_type ); pcommand->toi_class, pcommand->toi_type );
switch (action) 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)
{
ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO",
pcommand->toi_class);
return ERROR_BAD_ENVIRONMENT;
}
switch (pcommand->toi_id) switch (pcommand->toi_id)
{ {
/* /* ENTITY_LIST_ID gets the list of "entity IDs", where an entity
ENTITY_LIST_ID seems to get number of adapters in the system. may represent an interface, or a datagram service, or address
(almost like an index to be used when calling other WsControl options) 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: case ENTITY_LIST_ID:
{ {
TDIEntityID *baseptr = pResponseInfo; TDIEntityID *baseptr = (TDIEntityID *)pResponseInfo;
DWORD numInt, i, ipAddrTableSize; DWORD numInt, i, ifTable, spaceNeeded;
PMIB_IPADDRTABLE table; PMIB_IFTABLE table;
if (pcommand->toi_class != INFO_CLASS_GENERIC && if (!pcbResponseInfoLen)
pcommand->toi_type != INFO_TYPE_PROVIDER) return ERROR_BAD_ENVIRONMENT;
if (pcommand->toi_class != INFO_CLASS_GENERIC)
{ {
FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n", FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx",
pcommand->toi_class, pcommand->toi_type); pcommand->toi_class);
return (WSAEOPNOTSUPP); return (ERROR_BAD_ENVIRONMENT);
} }
GetNumberOfInterfaces(&numInt); GetNumberOfInterfaces(&numInt);
spaceNeeded = sizeof(TDIEntityID) * (numInt + 4);
if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) ) if (*pcbResponseInfoLen < spaceNeeded)
return (ERROR_LOCK_VIOLATION);
ifTable = 0;
GetIfTable(NULL, &ifTable, FALSE);
table = (PMIB_IFTABLE)calloc(1, ifTable);
if (!table)
return ERROR_NOT_ENOUGH_MEMORY;
GetIfTable(table, &ifTable, FALSE);
spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
if (*pcbResponseInfoLen < spaceNeeded)
{ {
return (STATUS_BUFFER_TOO_SMALL); free(table);
return (ERROR_LOCK_VIOLATION);
} }
/* expect a 1:1 correspondence between interfaces and IP memset(baseptr, 0, spaceNeeded);
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++) for (i = 0; i < table->dwNumEntries; i++)
{ {
/* tei_instance is an network interface identifier. /* Return IF_GENERIC on every interface, and AT_ENTITY,
I'm not quite sure what the difference is between tei_entity values of * CL_NL_ENTITY, CL_TL_ENTITY, and CO_TL_ENTITY on the first
CL_NL_ENTITY and IF_ENTITY */ * interface. MS returns them only on the loopback
baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; * interface, but it doesn't seem to matter.
baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; */
if (i == 0)
{
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++;
}
baseptr->tei_entity = IF_GENERIC;
baseptr->tei_instance = table->table[i].dwIndex;
baseptr++;
} }
/* Calculate size of out buffer */ *pcbResponseInfoLen = spaceNeeded;
*pcbResponseInfoLen = sizeof(TDIEntityID)*(table->dwNumEntries*2);
free(table); free(table);
break; break;
} }
/* Returns MIB-II statistics for an interface */
/* ENTITY_TYPE_ID is used to obtain simple information about a case ENTITY_TYPE_ID:
network card, such as MAC Address, description, interface type, switch (pcommand->toi_entity.tei_entity)
number of network addresses, etc. */
case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
{ {
if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER) case IF_GENERIC:
{ if (pcommand->toi_class == INFO_CLASS_GENERIC)
if (pcommand->toi_entity.tei_entity == IF_ENTITY)
{ {
if (!pcbResponseInfoLen)
return ERROR_BAD_ENVIRONMENT;
*((ULONG *)pResponseInfo) = IF_MIB; *((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); *pcbResponseInfoLen = sizeof(ULONG);
} }
} else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
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; MIB_IFROW row;
DWORD index = pcommand->toi_entity.tei_instance, ret; DWORD index = pcommand->toi_entity.tei_instance, ret;
DWORD size = sizeof(row) - sizeof(row.wszName) - DWORD size = sizeof(row) - sizeof(row.wszName) -
sizeof(row.bDescr); sizeof(row.bDescr);
if (!pcbResponseInfoLen)
return ERROR_BAD_ENVIRONMENT;
if (*pcbResponseInfoLen < size) if (*pcbResponseInfoLen < size)
{ return (ERROR_LOCK_VIOLATION);
return (STATUS_BUFFER_TOO_SMALL);
}
row.dwIndex = index; row.dwIndex = index;
ret = GetIfEntry(&row); ret = GetIfEntry(&row);
if (ret != NO_ERROR) if (ret != NO_ERROR)
{ {
ERR ("Error retrieving data for interface index %lu\n", index); ERR ("Error retrieving data for interface index %lu\n",
return -1; /* FIXME: better error code */ index);
return ret;
} }
size = sizeof(row) - sizeof(row.wszName) - size = sizeof(row) - sizeof(row.wszName) -
sizeof(row.bDescr) + row.dwDescrLen; sizeof(row.bDescr) + row.dwDescrLen;
if (*pcbResponseInfoLen < size) if (*pcbResponseInfoLen < size)
{ return (ERROR_LOCK_VIOLATION);
return (STATUS_BUFFER_TOO_SMALL);
}
memcpy(pResponseInfo, &row.dwIndex, size); memcpy(pResponseInfo, &row.dwIndex, size);
*pcbResponseInfoLen = size; *pcbResponseInfoLen = size;
} }
else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY) break;
{
/* This case is used to obtain general statistics about the
network */
if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS)) /* 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)
{ {
return (STATUS_BUFFER_TOO_SMALL); 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); GetIpStatistics((PMIB_IPSTATS)pResponseInfo);
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof(MIB_IPSTATS); *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; 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;
/* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a default:
particular network adapter */ 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: case IP_MIB_ADDRTABLE_ENTRY_ID:
{ {
DWORD index = pcommand->toi_entity.tei_instance; DWORD index = pcommand->toi_entity.tei_instance;
@ -263,18 +382,18 @@ DWORD WINAPI WsControl(DWORD protocoll,
PMIB_IPADDRTABLE table; PMIB_IPADDRTABLE table;
DWORD tableSize, i; DWORD tableSize, i;
if (!pcbResponseInfoLen)
return ERROR_BAD_ENVIRONMENT;
if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW)) if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
{ return (ERROR_LOCK_VIOLATION);
return (STATUS_BUFFER_TOO_SMALL);
}
/* overkill, get entire table, because there isn't an /* get entire table, because there isn't an exported function that
exported function that gets just one entry, and don't gets just one entry. */
necessarily want our own private export. */
tableSize = 0; tableSize = 0;
GetIpAddrTable(NULL, &tableSize, FALSE); GetIpAddrTable(NULL, &tableSize, FALSE);
table = (PMIB_IPADDRTABLE)calloc(1, tableSize); table = (PMIB_IPADDRTABLE)calloc(1, tableSize);
if (!table) return -1; /* FIXME: better error code */ if (!table)
return ERROR_NOT_ENOUGH_MEMORY;
GetIpAddrTable(table, &tableSize, FALSE); GetIpAddrTable(table, &tableSize, FALSE);
for (i = 0; i < table->dwNumEntries; i++) for (i = 0; i < table->dwNumEntries; i++)
{ {
@ -287,14 +406,10 @@ DWORD WINAPI WsControl(DWORD protocoll,
} }
free(table); free(table);
/************************************************************************/
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof(MIB_IPADDRROW); *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
break; break;
} }
/* This call returns the routing table. /* This call returns the routing table.
* No official documentation found, even the name of the command is unknown. * No official documentation found, even the name of the command is unknown.
* Work is based on * Work is based on
@ -310,24 +425,23 @@ DWORD WINAPI WsControl(DWORD protocoll,
PMIB_IPFORWARDTABLE table; PMIB_IPFORWARDTABLE table;
IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo; IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo;
if (!pcbResponseInfoLen)
return ERROR_BAD_ENVIRONMENT;
GetIpForwardTable(NULL, &routeTableSize, FALSE); GetIpForwardTable(NULL, &routeTableSize, FALSE);
numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE), 0) numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE), 0)
/ sizeof(MIB_IPFORWARDROW) + 1; / sizeof(MIB_IPFORWARDROW) + 1;
if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes) if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
{ return (ERROR_LOCK_VIOLATION);
return (STATUS_BUFFER_TOO_SMALL);
}
table = (PMIB_IPFORWARDTABLE)calloc(1, routeTableSize); table = (PMIB_IPFORWARDTABLE)calloc(1, routeTableSize);
if (!table) return -1; /* FIXME: better return value */ if (!table)
return ERROR_NOT_ENOUGH_MEMORY;
GetIpForwardTable(table, &routeTableSize, FALSE); GetIpForwardTable(table, &routeTableSize, FALSE);
memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes); memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
for (ndx = 0; ndx < table->dwNumEntries; ndx++) for (ndx = 0; ndx < table->dwNumEntries; ndx++)
{ {
winRouteTable->ire_addr = winRouteTable->ire_addr = table->table[ndx].dwForwardDest;
table->table[ndx].dwForwardDest; winRouteTable->ire_index = table->table[ndx].dwForwardIfIndex;
winRouteTable->ire_index =
table->table[ndx].dwForwardIfIndex;
winRouteTable->ire_metric = winRouteTable->ire_metric =
table->table[ndx].dwForwardMetric1; table->table[ndx].dwForwardMetric1;
/* winRouteTable->ire_option4 = /* winRouteTable->ire_option4 =
@ -353,11 +467,11 @@ DWORD WINAPI WsControl(DWORD protocoll,
default: 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", 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_id, pcommand->toi_entity.tei_entity,
pcommand->toi_class, pcommand->toi_type); pcommand->toi_entity.tei_instance, pcommand->toi_class);
return (WSAEOPNOTSUPP); return (ERROR_BAD_ENVIRONMENT);
} }
} }
@ -382,14 +496,12 @@ DWORD WINAPI WsControl(DWORD protocoll,
} }
default: default:
{ FIXME("Protocol Not Supported -> protocol=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n", protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
return (WSAEOPNOTSUPP); return (WSAEOPNOTSUPP);
}
}
}
return (WSCTL_SUCCESS); return (WSCTL_SUCCESS);
} }

View File

@ -6,9 +6,12 @@
* *
* The functionality of WsControl was created by observing its behaviour * The functionality of WsControl was created by observing its behaviour
* in Windows 98, so there are likely to be bugs with the assumptions * 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 2000 James Hatheway
* Copyright 2003 Juan Lang
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -28,8 +31,6 @@
#ifndef WSCONTROL_H_INCLUDED #ifndef WSCONTROL_H_INCLUDED
#define 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 #define WSCTL_SUCCESS 0
/* /*
@ -57,44 +58,6 @@ typedef struct TDIObjectID
unsigned long toi_id; unsigned long toi_id;
} TDIObjectID; } 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 #ifdef if_type
#undef if_type #undef if_type
#endif #endif
@ -114,7 +77,7 @@ typedef struct IFEntry
unsigned long if_mtu; unsigned long if_mtu;
unsigned long if_speed; unsigned long if_speed;
unsigned long if_physaddrlen; unsigned long if_physaddrlen;
uchar if_physaddr[MAX_PHYSADDR_SIZE]; unsigned char if_physaddr[MAX_PHYSADDR_SIZE];
unsigned long if_adminstatus; unsigned long if_adminstatus;
unsigned long if_operstatus; unsigned long if_operstatus;
unsigned long if_lastchange; unsigned long if_lastchange;
@ -131,7 +94,7 @@ typedef struct IFEntry
unsigned long if_outerrors; unsigned long if_outerrors;
unsigned long if_outqlen; unsigned long if_outqlen;
unsigned long if_descrlen; unsigned long if_descrlen;
uchar if_descr[1]; unsigned char if_descr[1];
} IFEntry; } IFEntry;
@ -153,34 +116,58 @@ typedef struct IPRouteEntry {
} IPRouteEntry; } IPRouteEntry;
/* Not sure what EXACTLY most of this stuff does. /* Constants for use in the toi_id field */
WsControl was implemented mainly by observing #define ENTITY_LIST_ID 0 /* to get the list of entity IDs */
its behaviour in Win98 ************************/ #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
/* Constants for use in the toi_class field */
#define INFO_CLASS_GENERIC 0x100 #define INFO_CLASS_GENERIC 0x100
#define INFO_CLASS_PROTOCOL 0x200 #define INFO_CLASS_PROTOCOL 0x200
/* Constants for use in the toi_type field */
#define INFO_TYPE_PROVIDER 0x100 #define INFO_TYPE_PROVIDER 0x100
#define ENTITY_LIST_ID 0
/* 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_ENTITY 0x301
#define IF_ENTITY 0x200 #define CL_NL_IPX 0x301 /* implements IPX--probably won't see this, since
#define ENTITY_TYPE_ID 1 * we're querying the TCP protocol */
#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102 #define CL_NL_IP 0x303 /* implements IP */
#define IP_MIB_ROUTETABLE_ENTRY_ID 0x101 /* FIXME: not real name */
/************************************************/
/* Valid values to get back from entity type ID query */ /* echo request/response types. The first can be returned in the entity ID
#define CO_TL_NBF 0x400 /* Entity implements NBF prot. */ * list--it can be further queried for what type of echo it supports (I think).
#define CO_TL_SPX 0x402 /* Entity implements SPX prot. */ */
#define CO_TL_TCP 0x404 /* Entity implements TCP prot. */ #define ER_ENTITY 0x380
#define CO_TL_SPP 0x406 /* Entity implements SPP prot. */ #define ER_ICMP 0x380
#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 */
/* 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 */ #endif /* WSCONTROL_H_INCLUDED */