* 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
#include "config.h"
+#include <stdarg.h>
-#include <sys/types.h>
#include "windef.h"
#include "winbase.h"
-#include "debugtools.h"
+#include "wine/debug.h"
#include "winsock2.h"
#include "winnt.h"
#include "wscontrol.h"
-#include <ctype.h>
-#include <sys/ioctl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#ifdef HAVE_SYS_SOCKIO_H
-# include <sys/sockio.h>
-#endif
-#ifdef HAVE_NET_IF_H
-# include <net/if.h>
-#endif
+#include "iphlpapi.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winsock);
+
+/* internal remapper function for the IP_ constants */
+static INT _remap_optname(INT level, INT optname)
+{
+ TRACE("level=%d, optname=%d\n", level, optname);
+ if (level == IPPROTO_IP) {
+ switch (optname) { /***** from value *****/
+ case 2: return 9; /* IP_MULTICAST_IF */
+ case 3: return 10; /* IP_MULTICAST_TTL */
+ case 4: return 11; /* IP_MULTICAST_LOOP */
+ case 5: return 12; /* IP_ADD_MEMBERSHIP */
+ case 6: return 13; /* IP_DROP_MEMBERSHIP */
+ case 7: return 4; /* IP_TTL */
+ case 8: return 3; /* IP_TOS */
+ case 9: return 14; /* IP_DONTFRAGMENT */
+ default: FIXME("Unknown optname %d, can't remap!\n", optname); return optname;
+ }
+ } else {
+ /* don't need to do anything */
+ return optname;
+ }
+}
-DEFAULT_DEBUG_CHANNEL(winsock);
+/***********************************************************************
+ * setsockopt (WSOCK32.21)
+ *
+ * We have these forwarders because, for reasons unknown to us mere mortals,
+ * the values of the IP_ constants changed between winsock.h and winsock2.h.
+ * So, we need to remap them here.
+ */
+INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
+{
+ return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
+}
-static INT (WINAPI *WS2_recv)(SOCKET s, char *buf, INT len, INT flags);
+/***********************************************************************
+ * getsockopt (WSOCK32.7)
+ */
+INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
+{
+ return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
+}
/***********************************************************************
- * WsControl()
+ * WsControl (WSOCK32.1001)
*
- * WsControl seems to be an undocumented Win95 function. A lot of
+ * WsControl seems to be an undocumented Win95 function. A lot of
* discussion about WsControl can be found on the net, e.g.
* Subject: Re: WSOCK32.DLL WsControl Exported Function
* From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
* Date: 1997/08/17
*
- * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
- * on observing the behaviour of WsControl with an app in
+ * 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,
LPVOID pResponseInfo,
- LPDWORD pcbResponseInfoLen)
+ LPDWORD pcbResponseInfoLen)
{
+
/* Get the command structure into a pointer we can use,
rather than void */
- TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
-
- 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 );
-
+ TDIObjectID *pcommand = 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 );
- 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\n",
+ 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
+ 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 = 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;
- int numInt = 0, i;
-
- 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);
- }
-
- numInt = WSCNTL_GetInterfaceCount();
- if (numInt < 0)
- {
- ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
- return (-1);
- }
+ FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx\n",
+ pcommand->toi_class);
+ return (ERROR_BAD_ENVIRONMENT);
+ }
- if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
-
- /* 0 it out first */
- memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
-
- for (i=0; i<numInt; 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 = i; baseptr++;
- baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
- }
+ GetNumberOfInterfaces(&numInt);
+ spaceNeeded = sizeof(TDIEntityID) * (numInt * 2 + 3);
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
-
- break;
+ if (*pcbResponseInfoLen < spaceNeeded)
+ return (ERROR_LOCK_VIOLATION);
+
+ ifTable = 0;
+ GetIfTable(NULL, &ifTable, FALSE);
+ table = HeapAlloc( GetProcessHeap(), 0, ifTable );
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ GetIfTable(table, &ifTable, FALSE);
+
+ spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
+ if (*pcbResponseInfoLen < spaceNeeded)
+ {
+ HeapFree( GetProcessHeap(), 0, table );
+ return ERROR_LOCK_VIOLATION;
}
-
-
- /* 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 */
+
+ memset(baseptr, 0, spaceNeeded);
+
+ for (i = 0; i < table->dwNumEntries; i++)
{
- if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
+ /* Return IF_GENERIC and CL_NL_ENTITY on every interface, and
+ * AT_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);
+ 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 = AT_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 = IF_GENERIC;
+ baseptr->tei_instance = table->table[i].dwIndex;
+ baseptr++;
+ }
- }
- else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
- {
- * ((ULONG *)pResponseInfo) = CL_NL_IP;
+ *pcbResponseInfoLen = spaceNeeded;
+ HeapFree( GetProcessHeap(), 0, table );
+ break;
+ }
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof (ULONG);
- }
+ /* 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 &&
- pcommand->toi_type == INFO_TYPE_PROVIDER)
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
{
- if (pcommand->toi_entity.tei_entity == IF_ENTITY)
- {
- /* In this case, we are requesting specific information about a
- a particular network adapter. (MAC Address, speed, data transmitted/received,
- etc.)
- */
- IFEntry *IntInfo = (IFEntry *) pResponseInfo;
- char ifName[512];
- struct ifreq ifInfo;
- int sock;
-
-
- if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
- {
- ERR ("Unable to parse /proc filesystem!\n");
- return (-1);
- }
-
- /* Get a socket so that we can use ioctl */
- if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- ERR ("Error creating socket!\n");
- return (-1);
- }
-
- /* 0 out return structure first */
- memset (IntInfo, 0, sizeof(IFEntry));
-
- /* Interface ID */
- IntInfo->if_index = pcommand->toi_entity.tei_instance;
-
- /* MAC Address - Let's try to do this in a cross-platform way... */
- #if defined(SIOCGIFHWADDR) /* Linux */
- strcpy(ifInfo.ifr_name, ifName);
- if (ioctl(sock, SIOCGIFHWADDR, &ifInfo) < 0)
- {
- ERR ("Error obtaining MAC Address!\n");
- close(sock);
- return (-1);
- }
- else
- {
- /* FIXME: Is it correct to assume size of 6? */
- memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
- IntInfo->if_physaddrlen=6;
- }
- #elif defined(SIOCGENADDR) /* Solaris */
- if (ioctl(sock, SIOCGENADDR, &ifInfo) < 0)
- {
- ERR ("Error obtaining MAC Address!\n");
- close(sock);
- return (-1);
- }
- else
- {
- /* FIXME: Is it correct to assume size of 6? */
- memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
- IntInfo->if_physaddrlen=6;
- }
- #else
- memset (IntInfo->if_physaddr, 0, 6);
- ERR ("Unable to determine MAC Address on your platform!\n");
- #endif
-
-
- /* Interface name and length */
- strcpy (IntInfo->if_descr, ifName);
- IntInfo->if_descrlen= strlen (IntInfo->if_descr);
-
- /* Obtain bytes transmitted/received for interface */
- if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
- &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
- {
- ERR ("Error obtaining transmit/receive stats for the network interface!\n");
- close(sock);
- return (-1);
- }
-
-
- /* FIXME: How should the below be properly calculated? ******************/
- IntInfo->if_type = 0x6; /* Ethernet (?) */
- IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
- /************************************************************************/
-
- close(sock);
- *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
- }
- else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
+ 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)
{
- IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
- int numInt;
-
- /* This case is used to obtain general statistics about the
- network */
-
- if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
- {
- return (STATUS_BUFFER_TOO_SMALL);
- }
- else
- {
- /* 0 it out first */
- memset(infoStruc, 0, sizeof(IPSNMPInfo));
-
- /* Get the number of interfaces */
- numInt = WSCNTL_GetInterfaceCount();
- if (numInt < 0)
- {
- ERR ("Unable to open /proc filesystem to determine number of network interfaces!\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? */
-
- /* FIXME: How should the below be properly calculated? ******************/
- infoStruc->ipsi_forwarding = 0x0;
- infoStruc->ipsi_defaultttl = 0x0;
- infoStruc->ipsi_inreceives = 0x0;
- infoStruc->ipsi_inhdrerrors = 0x0;
- infoStruc->ipsi_inaddrerrors = 0x0;
- infoStruc->ipsi_forwdatagrams = 0x0;
- infoStruc->ipsi_inunknownprotos = 0x0;
- infoStruc->ipsi_indiscards = 0x0;
- infoStruc->ipsi_indelivers = 0x0;
- infoStruc->ipsi_outrequests = 0x0;
- infoStruc->ipsi_routingdiscards = 0x0;
- infoStruc->ipsi_outdiscards = 0x0;
- infoStruc->ipsi_outnoroutes = 0x0;
- infoStruc->ipsi_reasmtimeout = 0x0;
- infoStruc->ipsi_reasmreqds = 0x0;
- infoStruc->ipsi_reasmoks = 0x0;
- infoStruc->ipsi_reasmfails = 0x0;
- infoStruc->ipsi_fragoks = 0x0;
- infoStruc->ipsi_fragfails = 0x0;
- infoStruc->ipsi_fragcreates = 0x0;
- /************************************************************************/
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof(IPSNMPInfo);
- }
+ /* FIXME: Win98's arp.exe insists on querying index 1 for
+ * its MIB-II stats, regardless of the tei_instances
+ * returned in the ENTITY_LIST query above. If the query
+ * fails, arp.exe fails. So, I do this hack return value
+ * if index is 1 and the query failed just to get arp.exe
+ * to continue.
+ */
+ if (index == 1)
+ return NO_ERROR;
+ ERR ("Error retrieving data for interface index %u\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;
}
- 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;
- }
-
- /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
- particular network adapter */
- case IP_MIB_ADDRTABLE_ENTRY_ID:
- {
- IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
- char ifName[512];
- struct ifreq ifInfo;
- int sock;
-
- if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
+ /* Returns address-translation related data. In our case, this is
+ * ARP.
+ */
+ 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);
}
-
- if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
{
- ERR ("Unable to parse /proc filesystem!\n");
- return (-1);
+ PMIB_IPNETTABLE table;
+ DWORD size;
+ PULONG output = pResponseInfo;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(ULONG) * 2)
+ return (ERROR_LOCK_VIOLATION);
+ GetIpNetTable(NULL, &size, FALSE);
+ table = HeapAlloc( GetProcessHeap(), 0, 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;
+ HeapFree( GetProcessHeap(), 0, table );
+ *pcbResponseInfoLen = sizeof(ULONG) * 2;
}
-
-
- /* Get a socket so we can use ioctl */
- if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+ break;
+
+ /* Returns connectionless network layer statistics--in our case,
+ * this is IP.
+ */
+ case CL_NL_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
{
- ERR ("Error creating socket!\n");
- return (-1);
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = CL_NL_IP;
+ *pcbResponseInfoLen = sizeof(ULONG);
}
-
- /* 0 it out first */
- memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
-
- /* Interface Id */
- baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
-
- /* IP Address */
- strcpy (ifInfo.ifr_name, ifName);
- ifInfo.ifr_addr.sa_family = AF_INET;
- if (ioctl(sock, SIOCGIFADDR, &ifInfo) < 0)
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
{
- baseIPInfo->iae_addr = 0x0;
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
+ return ERROR_LOCK_VIOLATION;
+ GetIpStatistics(pResponseInfo);
+
+ *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
}
- else
+ break;
+
+ /* Returns connectionless transport layer statistics--in our case,
+ * this is UDP.
+ */
+ case CL_TL_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
{
- struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
- baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = CL_TL_UDP;
+ *pcbResponseInfoLen = sizeof(ULONG);
}
-
- /* Broadcast Address */
- strcpy (ifInfo.ifr_name, ifName);
- if (ioctl(sock, SIOCGIFBRDADDR, &ifInfo) < 0)
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
{
- baseIPInfo->iae_bcastaddr = 0x0;
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS))
+ return ERROR_LOCK_VIOLATION;
+ GetUdpStatistics(pResponseInfo);
+ *pcbResponseInfoLen = sizeof(MIB_UDPSTATS);
}
- else
+ break;
+
+ /* Returns connection-oriented transport layer statistics--in our
+ * case, this is TCP.
+ */
+ case CO_TL_ENTITY:
+ if (pcommand->toi_class == INFO_CLASS_GENERIC)
{
- struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
- baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ *((ULONG *)pResponseInfo) = CO_TL_TCP;
+ *pcbResponseInfoLen = sizeof(ULONG);
}
-
- /* Subnet Mask */
- strcpy(ifInfo.ifr_name, ifName);
- if (ioctl(sock, SIOCGIFNETMASK, &ifInfo) < 0)
+ else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
{
- baseIPInfo->iae_mask = 0x0;
- }
- else
- {
- /* Trying to avoid some compile problems across platforms.
- (Linux, FreeBSD, Solaris...) */
- #ifndef ifr_netmask
- #ifndef ifr_addr
- baseIPInfo->iae_mask = 0;
- ERR ("Unable to determine Netmask on your platform!\n");
- #else
- struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
- baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
- #endif
- #else
- struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
- baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
- #endif
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS))
+ return ERROR_LOCK_VIOLATION;
+ GetTcpStatistics(pResponseInfo);
+ *pcbResponseInfoLen = sizeof(MIB_TCPSTATS);
}
-
- /* FIXME: How should the below be properly calculated? ******************/
- baseIPInfo->iae_reasmsize = 0x0;
- baseIPInfo->iae_context = 0x0;
- baseIPInfo->iae_pad = 0x0;
- /************************************************************************/
-
- /* Calculate size of out buffer */
- *pcbResponseInfoLen = sizeof(IPAddrEntry);
- close(sock);
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);
- }
+ default:
+ ERR("Unknown entity %ld for ENTITY_TYPE_ID query\n",
+ pcommand->toi_entity.tei_entity);
}
-
- 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("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);
- }
- }
-
-
- return (WSCTL_SUCCESS);
-}
-
-
-
-/*
- Helper function for WsControl - Get count of the number of interfaces
- by parsing /proc filesystem.
-*/
-int WSCNTL_GetInterfaceCount(void)
-{
- FILE *procfs;
- char buf[512]; /* Size doesn't matter, something big */
- int intcnt=0;
-
-
- /* 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))
- {
- /* Each line in the file represents a network interface */
- intcnt++;
- }
-
- fclose(procfs);
- return(intcnt);
-}
-
-
-/*
- Helper function for WsControl - Get name of device from interface number
- by parsing /proc filesystem.
-*/
-int WSCNTL_GetInterfaceName(int intNumber, char *intName)
-{
- FILE *procfs;
- char buf[512]; /* Size doesn't matter, something big */
- int i;
- /* 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);
-
- for (i=0; i<intNumber; i++)
- {
- /* Skip the lines that don't interest us. */
- fgets(buf, sizeof(buf), procfs);
- }
- fgets(buf, sizeof(buf), procfs); /* This is the line we want */
-
-
- /* Parse out the line, grabbing only the name of the device
- to the intName variable
-
- The Line comes in like this: (we only care about the device name)
- lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
- */
- i=0;
- while (isspace(buf[i])) /* Skip initial space(s) */
- {
- i++;
- }
-
- while (buf[i])
- {
- if (isspace(buf[i]))
- {
- break;
- }
-
- if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
- {
- /* This interface could be an alias... */
- int hold = i;
- char *dotname = intName;
- *intName++ = buf[i++];
-
- while (isdigit(buf[i]))
- {
- *intName++ = buf[i++];
- }
-
- if (buf[i] != ':')
+ /* 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:
{
- /* ... It wasn't, so back up */
- i = hold;
- intName = dotname;
+ DWORD index = pcommand->toi_entity.tei_instance;
+ PMIB_IPADDRROW baseIPInfo = 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 = HeapAlloc( GetProcessHeap(), 0, 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)
+ {
+ TRACE("Found IP info for tei_instance 0x%x:\n", index);
+ TRACE("IP 0x%08x, mask 0x%08x\n", table->table[i].dwAddr,
+ table->table[i].dwMask);
+ *baseIPInfo = table->table[i];
+ break;
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, table );
+
+ *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
+ break;
}
-
- if (buf[i] == '\0')
+
+ case IP_MIB_TABLE_ENTRY_ID:
{
- fclose(procfs);
- return(FALSE);
- }
-
- i++;
- break;
- }
-
- *intName++ = buf[i++];
- }
- *intName++ = '\0';
+ switch (pcommand->toi_entity.tei_entity)
+ {
+ /* 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 CL_NL_ENTITY:
+ {
+ DWORD routeTableSize, numRoutes, ndx, ret;
+ PMIB_IPFORWARDTABLE table;
+ IPRouteEntry *winRouteTable = pResponseInfo;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ ret = GetIpForwardTable(NULL, &routeTableSize, FALSE);
+ if (ret != ERROR_INSUFFICIENT_BUFFER)
+ return ret;
+ numRoutes = (routeTableSize - sizeof(MIB_IPFORWARDTABLE))
+ / sizeof(MIB_IPFORWARDROW) + 1;
+ if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
+ return (ERROR_LOCK_VIOLATION);
+ table = HeapAlloc( GetProcessHeap(), 0, routeTableSize );
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ ret = GetIpForwardTable(table, &routeTableSize, FALSE);
+ if (ret != NO_ERROR) {
+ HeapFree( GetProcessHeap(), 0, table );
+ return ret;
+ }
- fclose(procfs);
- return(TRUE);
-}
+ 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;
-/*
- Helper function for WsControl - This function returns the bytes (octets) transmitted
- and received for the supplied interface number from the /proc fs.
-*/
-int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
-{
- FILE *procfs;
- char buf[512], result[512]; /* Size doesn't matter, something big */
- int i, bufPos, resultPos;
+ HeapFree( GetProcessHeap(), 0, table );
+ }
+ break;
- /* 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);
+ case AT_ARP:
+ {
+ DWORD arpTableSize, numEntries, ret;
+ PMIB_IPNETTABLE table;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ ret = GetIpNetTable(NULL, &arpTableSize, FALSE);
+ if (ret != ERROR_INSUFFICIENT_BUFFER)
+ return ret;
+ numEntries = (arpTableSize - sizeof(MIB_IPNETTABLE))
+ / sizeof(MIB_IPNETROW) + 1;
+ if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * numEntries)
+ return (ERROR_LOCK_VIOLATION);
+ table = HeapAlloc( GetProcessHeap(), 0, arpTableSize );
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ ret = GetIpNetTable(table, &arpTableSize, FALSE);
+ if (ret != NO_ERROR) {
+ HeapFree( GetProcessHeap(), 0, table );
+ return ret;
+ }
+ if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) *
+ table->dwNumEntries)
+ {
+ HeapFree( GetProcessHeap(), 0, table );
+ return ERROR_LOCK_VIOLATION;
+ }
+ memcpy(pResponseInfo, table->table, sizeof(MIB_IPNETROW) *
+ table->dwNumEntries);
- for (i=0; i<intNumber; i++)
- {
- /* Skip the lines that don't interest us. */
- fgets(buf, sizeof(buf), procfs);
- }
- fgets(buf, sizeof(buf), procfs); /* This is the line we want */
+ /* calculate the length of the data in the output buffer */
+ *pcbResponseInfoLen = sizeof(MIB_IPNETROW) *
+ table->dwNumEntries;
+ HeapFree( GetProcessHeap(), 0, table );
+ }
+ break;
+ case CO_TL_ENTITY:
+ {
+ DWORD tcpTableSize, numEntries, ret;
+ PMIB_TCPTABLE table;
+ DWORD i;
+
+ if (!pcbResponseInfoLen)
+ return ERROR_BAD_ENVIRONMENT;
+ ret = GetTcpTable(NULL, &tcpTableSize, FALSE);
+ if (ret != ERROR_INSUFFICIENT_BUFFER)
+ return ret;
+ numEntries = (tcpTableSize - sizeof(MIB_TCPTABLE))
+ / sizeof(MIB_TCPROW) + 1;
+ if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * numEntries)
+ return (ERROR_LOCK_VIOLATION);
+ table = HeapAlloc( GetProcessHeap(), 0, tcpTableSize );
+ if (!table)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ ret = GetTcpTable(table, &tcpTableSize, FALSE);
+ if (ret != NO_ERROR) {
+ HeapFree( GetProcessHeap(), 0, table );
+ return ret;
+ }
+ if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) *
+ table->dwNumEntries)
+ {
+ HeapFree( GetProcessHeap(), 0, table );
+ return ERROR_LOCK_VIOLATION;
+ }
+ for (i = 0; i < table->dwNumEntries; i++)
+ {
+ USHORT sPort;
- /* Parse out the line, grabbing the number of bytes transmitted
- and received on the interface.
-
- The Line comes in like this: (we care about columns 2 and 10)
- lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
- */
+ sPort = ntohs((USHORT)table->table[i].dwLocalPort);
+ table->table[i].dwLocalPort = (DWORD)sPort;
+ sPort = ntohs((USHORT)table->table[i].dwRemotePort);
+ table->table[i].dwRemotePort = (DWORD)sPort;
+ }
+ memcpy(pResponseInfo, table->table, sizeof(MIB_TCPROW) *
+ table->dwNumEntries);
- /* Start at character 0 in the buffer */
- bufPos=0;
-
- /* Skip initial space(s) */
- while (isspace(buf[bufPos]))
- bufPos++;
+ /* calculate the length of the data in the output buffer */
+ *pcbResponseInfoLen = sizeof(MIB_TCPROW) *
+ table->dwNumEntries;
+ HeapFree( GetProcessHeap(), 0, table );
+ }
+ break;
- /* Skip the name and its trailing spaces (if any) */
- while (buf[bufPos])
- {
- if (isspace(buf[bufPos]))
+ 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);
+ }
+ }
+ }
break;
-
- if (buf[bufPos] == ':') /* Could be an alias */
- {
- int hold = bufPos;
- while(isdigit (buf[bufPos]))
- bufPos++;
- if (buf[bufPos] != ':')
- bufPos = hold;
- if (buf[bufPos] == '\0')
+
+ default:
{
- fclose(procfs);
- return(FALSE);
+ 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);
}
-
- bufPos++;
- break;
}
- bufPos++;
+ break;
}
- while (isspace(buf[bufPos]))
- bufPos++;
-
- /* This column (#2) is the number of bytes received. */
- resultPos = 0;
- while (!isspace(buf[bufPos]))
+ case WSCNTL_TCPIP_ICMP_ECHO:
{
- result[resultPos] = buf[bufPos];
- result[resultPos+1]='\0';
- resultPos++; bufPos++;
- }
- *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
+ 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
-
- /* Skip columns #3 to #9 (Don't need them) */
- for (i=0; i<7; i++)
- {
- while (isspace(buf[bufPos]))
- bufPos++;
- while (!isspace(buf[bufPos]))
- bufPos++;
+ FIXME("(ICMP_ECHO) to 0x%08x stub\n", addr);
+ break;
}
+ default:
+ FIXME("Protocol Not Supported -> protocol=0x%x, action=0x%x, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
+ protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
- /* This column (#10) is the number of bytes transmitted */
- while (isspace(buf[bufPos]))
- bufPos++;
+ return (WSAEOPNOTSUPP);
- resultPos = 0;
- while (!isspace(buf[bufPos]))
- {
- result[resultPos] = buf[bufPos];
- result[resultPos+1]='\0';
- resultPos++; bufPos++;
}
- *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
-
- fclose(procfs);
- return(TRUE);
+ return (WSCTL_SUCCESS);
}
+
/***********************************************************************
- * WSARecvEx() (WSOCK32.1107)
+ * WSARecvEx (WSOCK32.1107)
*
* WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
* except that has an in/out argument call flags that has the value MSG_PARTIAL ored
*/
INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
{
- FIXME("(WSARecvEx) partial packet return value not set \n");
- return WS2_recv(s, buf, len, *flags);
+ FIXME("(WSARecvEx) partial packet return value not set\n");
+ return recv(s, buf, len, *flags);
}
/***********************************************************************
- * WS_s_perror (WSOCK32.1108)
+ * s_perror (WSOCK32.1108)
*/
-void WINAPI WS_s_perror(LPCSTR message)
+void WINAPI s_perror(LPCSTR message)
{
FIXME("(%s): stub\n",message);
return;
}
-
-
-/***********************************************************************
- * WSOCK_LibMain
- */
-BOOL WINAPI WSOCK_LibMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
-{
- static HMODULE ws2_32;
- switch (reason)
- {
- case DLL_PROCESS_ATTACH:
- /* we import ws2_32 by hand, because we don't want to implicitly */
- /* link to it; otherwise Unix calls like socket() get redirected */
- /* to ws2_32.dll and this is not what we want. */
-
- if (!(ws2_32 = LoadLibraryA( "ws2_32.dll" )))
- {
- ERR("could not load ws2_32\n" );
- return FALSE;
- }
- WS2_recv = (void *)GetProcAddress( ws2_32, "recv" );
- break;
- case DLL_PROCESS_DETACH:
- FreeLibrary( ws2_32 );
- break;
- }
- return TRUE;
-}