Commit c9d25827 authored by James Hatheway's avatar James Hatheway Committed by Alexandre Julliard

Adds an initial WSAIoctl function with support for only the

SIO_GET_INTERFACE_LIST command. Adds initial code to WsControl function to support the WSCNTL_TCPIP_QUERY_INFO command.
parent 67247b2b
......@@ -69,6 +69,9 @@
#ifdef HAVE_RESOLV_H
# include <resolv.h>
#endif
#ifdef HAVE_NET_IF_H
# include <net/if.h>
#endif
#include "wine/winbase16.h"
#include "wingdi.h"
......@@ -84,6 +87,7 @@
#include "server.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(winsock)
#define DEBUG_SOCKADDR 0
......@@ -119,6 +123,10 @@ typedef struct /* WSAAsyncSelect() control struct */
#define WSI_BLOCKINGCALL 0x00000001 /* per-thread info flags */
#define WSI_BLOCKINGHOOK 0x00000002 /* 32-bit callback */
#define PROCFS_NETDEV_FILE "/proc/net/dev" /* Points to the file in the /proc fs
that lists the network devices.
Do we need an #ifdef LINUX for this? */
typedef struct _WSINFO
{
DWORD dwThisProcess;
......@@ -148,6 +156,9 @@ int WS_dup_he(LPWSINFO pwsi, struct hostent* p_he, int flag);
int WS_dup_pe(LPWSINFO pwsi, struct protoent* p_pe, int flag);
int WS_dup_se(LPWSINFO pwsi, struct servent* p_se, int flag);
int WSAIOCTL_GetInterfaceCount(void);
int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
UINT16 wsaErrno(void);
UINT16 wsaHerrno(void);
......@@ -1270,6 +1281,280 @@ SEGPTR WINAPI WINSOCK_inet_ntoa16(struct in_addr in)
return retVal ? SEGPTR_GET(retVal) : (SEGPTR)NULL;
}
/**********************************************************************
* WSAIoctl (WS2_32)
*
*
* FIXME: Only SIO_GET_INTERFACE_LIST option implemented.
*/
INT WINAPI WSAIoctl (SOCKET s,
DWORD dwIoControlCode,
LPVOID lpvInBuffer,
DWORD cbInBuffer,
LPVOID lpbOutBuffer,
DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
LPWSINFO pwsi = WINSOCK_GetIData();
if( _check_ws(pwsi, s) )
{
int fd = _get_sock_fd(s);
switch( dwIoControlCode )
{
case SIO_GET_INTERFACE_LIST:
{
INTERFACE_INFO* intArray = (INTERFACE_INFO*)lpbOutBuffer;
int i, numInt;
struct ifreq ifInfo;
char ifName[512];
TRACE ("-> SIO_GET_INTERFACE_LIST request\n");
numInt = WSAIOCTL_GetInterfaceCount();
if (numInt < 0)
{
ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
close(fd);
WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR);
}
for (i=0; i<numInt; i++)
{
if (!WSAIOCTL_GetInterfaceName(i, ifName))
{
ERR ("Error parsing /proc filesystem!\n");
close(fd);
WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR);
}
ifInfo.ifr_addr.sa_family = AF_INET;
/* IP Address */
strcpy (ifInfo.ifr_name, ifName);
if (ioctl(fd, SIOCGIFADDR, &ifInfo) < 0)
{
ERR ("Error obtaining IP address\n");
close(fd);
WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR);
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
intArray->iiAddress.AddressIn.sin_family = AF_INET;
intArray->iiAddress.AddressIn.sin_port = ipTemp->sin_port;
intArray->iiAddress.AddressIn.sin_addr.ws_addr = ipTemp->sin_addr.S_un.S_addr;
}
/* Broadcast Address */
strcpy (ifInfo.ifr_name, ifName);
if (ioctl(fd, SIOCGIFBRDADDR, &ifInfo) < 0)
{
ERR ("Error obtaining Broadcast IP address\n");
close(fd);
WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR);
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
intArray->iiBroadcastAddress.AddressIn.sin_family = AF_INET;
intArray->iiBroadcastAddress.AddressIn.sin_port = ipTemp->sin_port;
intArray->iiBroadcastAddress.AddressIn.sin_addr.ws_addr = ipTemp->sin_addr.S_un.S_addr;
}
/* Subnet Mask */
strcpy (ifInfo.ifr_name, ifName);
if (ioctl(fd, SIOCGIFNETMASK, &ifInfo) < 0)
{
ERR ("Error obtaining Subnet IP address\n");
close(fd);
WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR);
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
intArray->iiNetmask.AddressIn.sin_family = AF_INET;
intArray->iiNetmask.AddressIn.sin_port = ipTemp->sin_port;
intArray->iiNetmask.AddressIn.sin_addr.ws_addr = ipTemp->sin_addr.S_un.S_addr;
}
/* Socket Status Flags */
strcpy(ifInfo.ifr_name, ifName);
if (ioctl(fd, SIOCGIFFLAGS, &ifInfo) < 0)
{
ERR ("Error obtaining status flags for socket!\n");
close(fd);
WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR);
}
else
{
/* FIXME - Is this the right flag to use? */
intArray->iiFlags = ifInfo.ifr_flags;
}
intArray++; /* Prepare for another interface */
}
/* Calculate the size of the array being returned */
*lpcbBytesReturned = sizeof(INTERFACE_INFO) * numInt;
break;
}
default:
{
WARN("\tunsupported WS_IOCTL cmd (%08lx)\n", dwIoControlCode);
close(fd);
WSASetLastError(WSAEOPNOTSUPP);
return (SOCKET_ERROR);
}
}
/* Function executed with no errors */
close(fd);
return (0);
}
else
{
WSASetLastError(WSAENOTSOCK);
return (SOCKET_ERROR);
}
}
/*
Helper function for WSAIoctl - Get count of the number of interfaces
by parsing /proc filesystem.
*/
int WSAIOCTL_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 WSAIoctl - Get name of device from interface number
by parsing /proc filesystem.
*/
int WSAIOCTL_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] != ':')
{
/* ... It wasn't, so back up */
i = hold;
intName = dotname;
}
if (buf[i] == '\0')
{
fclose(procfs);
return(FALSE);
}
i++;
break;
}
*intName++ = buf[i++];
}
*intName++ = '\0';
fclose(procfs);
return(TRUE);
}
/***********************************************************************
* ioctlsocket() (WSOCK32.12)
*/
......
......@@ -56,7 +56,7 @@ init WSOCK32_LibMain
47 stub WSAHtons
48 stub WSAInstallServiceClassA
49 stub WSAInstallServiceClassW
50 stub WSAIoctl
50 stdcall WSAIoctl(long long ptr long ptr long ptr ptr ptr) WSAIoctl
51 stdcall gethostbyaddr(ptr long long) WSOCK32_gethostbyaddr
52 stdcall gethostbyname(str) WSOCK32_gethostbyname
53 stdcall getprotobyname(str) WSOCK32_getprotobyname
......
......@@ -4,30 +4,385 @@
* Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
*/
#include "config.h"
#include <sys/types.h>
#include "windef.h"
#include "debugtools.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_NET_IF_H
# include <net/if.h>
#endif
DEFAULT_DEBUG_CHANNEL(winsock);
/* TCP/IP action codes */
#define WSCNTL_TCPIP_QUERY_INFO 0x00000000
#define WSCNTL_TCPIP_SET_INFO 0x00000001
#define WSCNTL_TCPIP_ICMP_ECHO 0x00000002
#define WSCNTL_TCPIP_TEST 0x00000003
/***********************************************************************
* WsControl
* WsControl()
*
* 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
* 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().
*
*/
DWORD WINAPI WsControl(DWORD protocoll,DWORD action,
LPVOID inbuf,LPDWORD inbuflen,
LPVOID outbuf,LPDWORD outbuflen)
DWORD WINAPI WsControl(DWORD protocoll,
DWORD action,
LPVOID pRequestInfo,
LPDWORD pcbRequestInfoLen,
LPVOID pResponseInfo,
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 );
switch (action)
{
case WSCNTL_TCPIP_QUERY_INFO:
{
switch (pcommand->toi_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;
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);
}
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++;
}
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
break;
}
/* 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 */
{
if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
{
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);
}
}
else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
pcommand->toi_type == INFO_TYPE_PROVIDER)
{
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 */
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;
}
/* 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)
{
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);
}
}
}
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))
{
return (STATUS_BUFFER_TOO_SMALL);
}
if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
{
ERR ("Unable to parse /proc filesystem!\n");
return (-1);
}
/* Get a socket so we can use ioctl */
if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
{
ERR ("Error creating socket!\n");
return (-1);
}
/* 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)
{
baseIPInfo->iae_addr = 0x0;
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
}
/* Broadcast Address */
strcpy (ifInfo.ifr_name, ifName);
if (ioctl(sock, SIOCGIFBRDADDR, &ifInfo) < 0)
{
baseIPInfo->iae_bcastaddr = 0x0;
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
}
/* Subnet Mask */
strcpy(ifInfo.ifr_name, ifName);
if (ioctl(sock, SIOCGIFNETMASK, &ifInfo) < 0)
{
baseIPInfo->iae_mask = 0x0;
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
}
/* 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);
}
}
break;
}
switch (action) {
case WSCNTL_TCPIP_ICMP_ECHO:
{
unsigned int addr = *(unsigned int*)inbuf;
#if 0
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);
......@@ -35,18 +390,266 @@ DWORD WINAPI WsControl(DWORD protocoll,DWORD action,
char ttl = *(unsigned char*)(inbuf+13);
char service = *(unsigned char*)(inbuf+14);
char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
#endif
#endif
FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
break;
}
default:
FIXME("(%lx,%lx,%p,%p,%p,%p) stub\n",
protocoll,action,inbuf,inbuflen,outbuf,outbuflen);
{
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 FALSE;
}
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] != ':')
{
/* ... It wasn't, so back up */
i = hold;
intName = dotname;
}
if (buf[i] == '\0')
{
fclose(procfs);
return(FALSE);
}
i++;
break;
}
*intName++ = buf[i++];
}
*intName++ = '\0';
fclose(procfs);
return(TRUE);
}
/*
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, ulong *transBytes, ulong *recvBytes)
{
FILE *procfs;
char buf[512], result[512]; /* Size doesn't matter, something big */
int i, bufPos, resultPos;
/* 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 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
*/
/* Start at character 0 in the buffer */
bufPos=0;
/* Skip initial space(s) */
while (isspace(buf[bufPos]))
bufPos++;
/* Skip the name and its trailing spaces (if any) */
while (buf[bufPos])
{
if (isspace(buf[bufPos]))
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')
{
fclose(procfs);
return(FALSE);
}
bufPos++;
break;
}
bufPos++;
}
while (isspace(buf[bufPos]))
bufPos++;
/* This column (#2) is the number of bytes received. */
resultPos = 0;
while (!isspace(buf[bufPos]))
{
result[resultPos] = buf[bufPos];
result[resultPos+1]='\0';
resultPos++; bufPos++;
}
*recvBytes = strtoul (result, NULL, 10); /* convert string to ulong, using base 10 */
/* 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++;
}
/* This column (#10) is the number of bytes transmitted */
while (isspace(buf[bufPos]))
bufPos++;
resultPos = 0;
while (!isspace(buf[bufPos]))
{
result[resultPos] = buf[bufPos];
result[resultPos+1]='\0';
resultPos++; bufPos++;
}
*transBytes = strtoul (result, NULL, 10); /* convert string to ulong, using base 10 */
fclose(procfs);
return(TRUE);
}
/***********************************************************************
* WS_s_perror (WSOCK32.1108)
*/
......
/* wscontrol.h
*
* This header file includes #defines, structure and type definitions,
* and function declarations that support the implementation of the
* (undocumented) Winsock 1 call WsControl.
*
* 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.
*/
#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
#define PROCFS_NETDEV_FILE "/proc/net/dev" /* Points to the file in the /proc fs
that lists the network devices.
Do we need an #ifdef LINUX for this? */
/* WsControl Helper Functions */
int WSCNTL_GetInterfaceCount(void); /* Obtains the number of network interfaces */
int WSCNTL_GetInterfaceName(int, char *); /* Obtains the name of an interface */
int WSCNTL_GetTransRecvStat(int intNumber, ulong *transBytes, ulong *recvBytes); /* Obtains bytes
recv'd/trans by interface */
/*
* TCP/IP action codes.
*/
#define WSCNTL_TCPIP_QUERY_INFO 0x00000000
#define WSCNTL_TCPIP_SET_INFO 0x00000001
#define WSCNTL_TCPIP_ICMP_ECHO 0x00000002
#define WSCNTL_TCPIP_TEST 0x00000003
/* Structure of an entity ID */
typedef struct TDIEntityID
{
ulong tei_entity;
ulong tei_instance;
} TDIEntityID;
/* Structure of an object ID */
typedef struct TDIObjectID
{
TDIEntityID toi_entity;
ulong toi_class;
ulong toi_type;
ulong toi_id;
} TDIObjectID;
typedef struct IPSNMPInfo
{
ulong ipsi_forwarding;
ulong ipsi_defaultttl;
ulong ipsi_inreceives;
ulong ipsi_inhdrerrors;
ulong ipsi_inaddrerrors;
ulong ipsi_forwdatagrams;
ulong ipsi_inunknownprotos;
ulong ipsi_indiscards;
ulong ipsi_indelivers;
ulong ipsi_outrequests;
ulong ipsi_routingdiscards;
ulong ipsi_outdiscards;
ulong ipsi_outnoroutes;
ulong ipsi_reasmtimeout;
ulong ipsi_reasmreqds;
ulong ipsi_reasmoks;
ulong ipsi_reasmfails;
ulong ipsi_fragoks;
ulong ipsi_fragfails;
ulong ipsi_fragcreates;
ulong ipsi_numif;
ulong ipsi_numaddr;
ulong ipsi_numroutes;
} IPSNMPInfo;
typedef struct IPAddrEntry
{
ulong iae_addr;
ulong iae_index;
ulong iae_mask;
ulong iae_bcastaddr;
ulong iae_reasmsize;
ushort iae_context;
ushort iae_pad;
} IPAddrEntry;
#define MAX_PHYSADDR_SIZE 8
#define MAX_IFDESCR_LEN 256
typedef struct IFEntry
{
ulong if_index;
ulong if_type;
ulong if_mtu;
ulong if_speed;
ulong if_physaddrlen;
uchar if_physaddr[MAX_PHYSADDR_SIZE];
ulong if_adminstatus;
ulong if_operstatus;
ulong if_lastchange;
ulong if_inoctets;
ulong if_inucastpkts;
ulong if_innucastpkts;
ulong if_indiscards;
ulong if_inerrors;
ulong if_inunknownprotos;
ulong if_outoctets;
ulong if_outucastpkts;
ulong if_outnucastpkts;
ulong if_outdiscards;
ulong if_outerrors;
ulong if_outqlen;
ulong if_descrlen;
uchar if_descr[1];
} IFEntry;
/* 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
/************************************************/
/* 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 */
#endif /* WSCONTROL_H_INCLUDED */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment