2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
9 FIXME: This hack is fixing a problem in WsControl. When we call socket(),
10 it is supposed to call into ws2_32's WSOCK32_socket.
11 The problem is that socket() is predefined in a linux system header that
12 we are including, which is different from the WINE definition.
13 (cdecl vs. stdapi) The result is stack corruption.
15 The correct answer to this problem is to make winsock.h not dependent
16 on system headers, that way all of our functions are defined consistently.
17 Until that happens we need this hack.
19 #define socket linux_socket
24 #include <sys/types.h>
27 #include "debugtools.h"
30 #include "wscontrol.h"
32 #include <sys/ioctl.h>
36 #ifdef HAVE_SYS_SOCKIO_H
37 # include <sys/sockio.h>
44 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
47 extern SOCKET WINAPI
socket(INT af
, INT type
, INT protocol
);
51 DEFAULT_DEBUG_CHANNEL(winsock
);
54 /***********************************************************************
57 * WsControl seems to be an undocumented Win95 function. A lot of
58 * discussion about WsControl can be found on the net, e.g.
59 * Subject: Re: WSOCK32.DLL WsControl Exported Function
60 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
63 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
64 * on observing the behaviour of WsControl with an app in
65 * Windows 98. It is not fully implemented, and there could
66 * be (are?) errors due to incorrect assumptions made.
69 * WsControl returns WSCTL_SUCCESS on success.
70 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
71 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
73 * It doesn't seem to generate errors that can be retrieved by
78 DWORD WINAPI
WsControl(DWORD protocoll
,
81 LPDWORD pcbRequestInfoLen
,
83 LPDWORD pcbResponseInfoLen
)
85 /* Get the command structure into a pointer we can use,
87 TDIObjectID
*pcommand
= (TDIObjectID
*)pRequestInfo
;
89 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
90 pcommand
->toi_id
, pcommand
->toi_entity
.tei_entity
, pcommand
->toi_entity
.tei_instance
,
91 pcommand
->toi_class
, pcommand
->toi_type
);
97 case WSCNTL_TCPIP_QUERY_INFO
:
99 switch (pcommand
->toi_id
)
102 ENTITY_LIST_ID seems to get number of adapters in the system.
103 (almost like an index to be used when calling other WsControl options)
107 TDIEntityID
*baseptr
= pResponseInfo
;
110 if (pcommand
->toi_class
!= INFO_CLASS_GENERIC
&&
111 pcommand
->toi_type
!= INFO_TYPE_PROVIDER
)
113 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
114 pcommand
->toi_class
, pcommand
->toi_type
);
115 return (WSAEOPNOTSUPP
);
118 numInt
= WSCNTL_GetInterfaceCount();
121 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
125 if (*pcbResponseInfoLen
< sizeof(TDIEntityID
)*(numInt
*2) )
127 return (STATUS_BUFFER_TOO_SMALL
);
131 memset(baseptr
, 0, sizeof(TDIEntityID
)*(numInt
*2));
133 for (i
=0; i
<numInt
; i
++)
135 /* tei_instance is an network interface identifier.
136 I'm not quite sure what the difference is between tei_entity values of
137 CL_NL_ENTITY and IF_ENTITY */
138 baseptr
->tei_entity
= CL_NL_ENTITY
; baseptr
->tei_instance
= i
; baseptr
++;
139 baseptr
->tei_entity
= IF_ENTITY
; baseptr
->tei_instance
= i
; baseptr
++;
142 /* Calculate size of out buffer */
143 *pcbResponseInfoLen
= sizeof(TDIEntityID
)*(numInt
*2);
149 /* ENTITY_TYPE_ID is used to obtain simple information about a
150 network card, such as MAC Address, description, interface type,
151 number of network addresses, etc. */
152 case ENTITY_TYPE_ID
: /* ALSO: IP_MIB_STATS_ID */
154 if (pcommand
->toi_class
== INFO_CLASS_GENERIC
&& pcommand
->toi_type
== INFO_TYPE_PROVIDER
)
156 if (pcommand
->toi_entity
.tei_entity
== IF_ENTITY
)
158 * ((ULONG
*)pResponseInfo
) = IF_MIB
;
160 /* Calculate size of out buffer */
161 *pcbResponseInfoLen
= sizeof (ULONG
);
164 else if (pcommand
->toi_entity
.tei_entity
== CL_NL_ENTITY
)
166 * ((ULONG
*)pResponseInfo
) = CL_NL_IP
;
168 /* Calculate size of out buffer */
169 *pcbResponseInfoLen
= sizeof (ULONG
);
172 else if (pcommand
->toi_class
== INFO_CLASS_PROTOCOL
&&
173 pcommand
->toi_type
== INFO_TYPE_PROVIDER
)
175 if (pcommand
->toi_entity
.tei_entity
== IF_ENTITY
)
177 /* In this case, we are requesting specific information about a
178 a particular network adapter. (MAC Address, speed, data transmitted/received,
181 IFEntry
*IntInfo
= (IFEntry
*) pResponseInfo
;
187 if (!WSCNTL_GetInterfaceName(pcommand
->toi_entity
.tei_instance
, ifName
))
189 ERR ("Unable to parse /proc filesystem!\n");
193 /* Get a socket so that we can use ioctl */
194 if ( (sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) < 0)
196 ERR ("Error creating socket!\n");
200 /* 0 out return structure first */
201 memset (IntInfo
, 0, sizeof(IFEntry
));
204 IntInfo
->if_index
= pcommand
->toi_entity
.tei_instance
;
206 /* MAC Address - Let's try to do this in a cross-platform way... */
207 #if defined(SIOCGIFHWADDR) /* Linux */
208 strcpy(ifInfo
.ifr_name
, ifName
);
209 if (ioctlsocket(sock
, SIOCGIFHWADDR
, (ULONG
*)&ifInfo
) < 0)
211 ERR ("Error obtaining MAC Address!\n");
217 /* FIXME: Is it correct to assume size of 6? */
218 memcpy(IntInfo
->if_physaddr
, ifInfo
.ifr_hwaddr
.sa_data
, 6);
219 IntInfo
->if_physaddrlen
=6;
221 #elif defined(SIOCGENADDR) /* Solaris */
222 if (ioctlsocket(sock
, SIOCGENADDR
, (ULONG
*)&ifInfo
) < 0)
224 ERR ("Error obtaining MAC Address!\n");
230 /* FIXME: Is it correct to assume size of 6? */
231 memcpy(IntInfo
->if_physaddr
, ifInfo
.ifr_enaddr
, 6);
232 IntInfo
->if_physaddrlen
=6;
235 memset (IntInfo
->if_physaddr
, 0, 6);
236 ERR ("Unable to determine MAC Address on your platform!\n");
240 /* Interface name and length */
241 strcpy (IntInfo
->if_descr
, ifName
);
242 IntInfo
->if_descrlen
= strlen (IntInfo
->if_descr
);
244 /* Obtain bytes transmitted/received for interface */
245 if ( (WSCNTL_GetTransRecvStat(pcommand
->toi_entity
.tei_instance
,
246 &IntInfo
->if_inoctets
, &IntInfo
->if_outoctets
)) < 0)
248 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
254 /* FIXME: How should the below be properly calculated? ******************/
255 IntInfo
->if_type
= 0x6; /* Ethernet (?) */
256 IntInfo
->if_speed
= 1000000; /* Speed of interface (bits per second?) */
257 /************************************************************************/
260 *pcbResponseInfoLen
= sizeof (IFEntry
) + IntInfo
->if_descrlen
;
262 else if (pcommand
->toi_entity
.tei_entity
== CL_NL_ENTITY
)
264 IPSNMPInfo
*infoStruc
= (IPSNMPInfo
*) pResponseInfo
;
267 /* This case is used to obtain general statistics about the
270 if (*pcbResponseInfoLen
< sizeof(IPSNMPInfo
) )
272 return (STATUS_BUFFER_TOO_SMALL
);
277 memset(infoStruc
, 0, sizeof(IPSNMPInfo
));
279 /* Get the number of interfaces */
280 numInt
= WSCNTL_GetInterfaceCount();
283 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
287 infoStruc
->ipsi_numif
= numInt
; /* # of interfaces */
288 infoStruc
->ipsi_numaddr
= numInt
; /* # of addresses */
289 infoStruc
->ipsi_numroutes
= numInt
; /* # of routes ~ FIXME - Is this right? */
291 /* FIXME: How should the below be properly calculated? ******************/
292 infoStruc
->ipsi_forwarding
= 0x0;
293 infoStruc
->ipsi_defaultttl
= 0x0;
294 infoStruc
->ipsi_inreceives
= 0x0;
295 infoStruc
->ipsi_inhdrerrors
= 0x0;
296 infoStruc
->ipsi_inaddrerrors
= 0x0;
297 infoStruc
->ipsi_forwdatagrams
= 0x0;
298 infoStruc
->ipsi_inunknownprotos
= 0x0;
299 infoStruc
->ipsi_indiscards
= 0x0;
300 infoStruc
->ipsi_indelivers
= 0x0;
301 infoStruc
->ipsi_outrequests
= 0x0;
302 infoStruc
->ipsi_routingdiscards
= 0x0;
303 infoStruc
->ipsi_outdiscards
= 0x0;
304 infoStruc
->ipsi_outnoroutes
= 0x0;
305 infoStruc
->ipsi_reasmtimeout
= 0x0;
306 infoStruc
->ipsi_reasmreqds
= 0x0;
307 infoStruc
->ipsi_reasmoks
= 0x0;
308 infoStruc
->ipsi_reasmfails
= 0x0;
309 infoStruc
->ipsi_fragoks
= 0x0;
310 infoStruc
->ipsi_fragfails
= 0x0;
311 infoStruc
->ipsi_fragcreates
= 0x0;
312 /************************************************************************/
314 /* Calculate size of out buffer */
315 *pcbResponseInfoLen
= sizeof(IPSNMPInfo
);
321 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
322 pcommand
->toi_class
, pcommand
->toi_type
);
324 return (WSAEOPNOTSUPP
);
331 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
332 particular network adapter */
333 case IP_MIB_ADDRTABLE_ENTRY_ID
:
335 IPAddrEntry
*baseIPInfo
= (IPAddrEntry
*) pResponseInfo
;
340 if (*pcbResponseInfoLen
< sizeof(IPAddrEntry
))
342 return (STATUS_BUFFER_TOO_SMALL
);
345 if (!WSCNTL_GetInterfaceName(pcommand
->toi_entity
.tei_instance
, ifName
))
347 ERR ("Unable to parse /proc filesystem!\n");
352 /* Get a socket so we can use ioctl */
353 if ( (sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) < 0)
355 ERR ("Error creating socket!\n");
360 memset(baseIPInfo
, 0, sizeof(IPAddrEntry
) );
363 baseIPInfo
->iae_index
= pcommand
->toi_entity
.tei_instance
;
366 strcpy (ifInfo
.ifr_name
, ifName
);
367 ifInfo
.ifr_addr
.sa_family
= AF_INET
;
368 if (ioctlsocket(sock
, SIOCGIFADDR
, (ULONG
*)&ifInfo
) < 0)
370 baseIPInfo
->iae_addr
= 0x0;
374 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_addr
;
375 baseIPInfo
->iae_addr
= ipTemp
->sin_addr
.S_un
.S_addr
;
378 /* Broadcast Address */
379 strcpy (ifInfo
.ifr_name
, ifName
);
380 if (ioctlsocket(sock
, SIOCGIFBRDADDR
, (ULONG
*)&ifInfo
) < 0)
382 baseIPInfo
->iae_bcastaddr
= 0x0;
386 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_broadaddr
;
387 baseIPInfo
->iae_bcastaddr
= ipTemp
->sin_addr
.S_un
.S_addr
;
391 strcpy(ifInfo
.ifr_name
, ifName
);
392 if (ioctlsocket(sock
, SIOCGIFNETMASK
, (ULONG
*)&ifInfo
) < 0)
394 baseIPInfo
->iae_mask
= 0x0;
398 /* Trying to avoid some compile problems across platforms.
399 (Linux, FreeBSD, Solaris...) */
402 baseIPInfo
->iae_mask
= 0;
403 ERR ("Unable to determine Netmask on your platform!\n");
405 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_addr
;
406 baseIPInfo
->iae_mask
= ipTemp
->sin_addr
.S_un
.S_addr
;
409 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_netmask
;
410 baseIPInfo
->iae_mask
= ipTemp
->sin_addr
.S_un
.S_addr
;
414 /* FIXME: How should the below be properly calculated? ******************/
415 baseIPInfo
->iae_reasmsize
= 0x0;
416 baseIPInfo
->iae_context
= 0x0;
417 baseIPInfo
->iae_pad
= 0x0;
418 /************************************************************************/
420 /* Calculate size of out buffer */
421 *pcbResponseInfoLen
= sizeof(IPAddrEntry
);
427 FIXME ("Command ID Unknown but used by winipcfg.exe\n");
433 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",
434 pcommand
->toi_id
, pcommand
->toi_entity
.tei_entity
, pcommand
->toi_entity
.tei_instance
,
435 pcommand
->toi_class
, pcommand
->toi_type
);
437 return (WSAEOPNOTSUPP
);
444 case WSCNTL_TCPIP_ICMP_ECHO
:
446 unsigned int addr
= *(unsigned int*)pRequestInfo
;
448 int timeout
= *(unsigned int*)(inbuf
+4);
449 short x1
= *(unsigned short*)(inbuf
+8);
450 short sendbufsize
= *(unsigned short*)(inbuf
+10);
451 char x2
= *(unsigned char*)(inbuf
+12);
452 char ttl
= *(unsigned char*)(inbuf
+13);
453 char service
= *(unsigned char*)(inbuf
+14);
454 char type
= *(unsigned char*)(inbuf
+15); /* 0x2: don't fragment*/
457 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr
);
463 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
464 protocoll
, action
, pRequestInfo
, pcbRequestInfoLen
, pResponseInfo
, pcbResponseInfoLen
);
466 return (WSAEOPNOTSUPP
);
471 return (WSCTL_SUCCESS
);
477 Helper function for WsControl - Get count of the number of interfaces
478 by parsing /proc filesystem.
480 int WSCNTL_GetInterfaceCount(void)
483 char buf
[512]; /* Size doesn't matter, something big */
487 /* Open /proc filesystem file for network devices */
488 procfs
= fopen(PROCFS_NETDEV_FILE
, "r");
491 /* If we can't open the file, return an error */
495 /* Omit first two lines, they are only headers */
496 fgets(buf
, sizeof buf
, procfs
);
497 fgets(buf
, sizeof buf
, procfs
);
499 while (fgets(buf
, sizeof buf
, procfs
))
501 /* Each line in the file represents a network interface */
511 Helper function for WsControl - Get name of device from interface number
512 by parsing /proc filesystem.
514 int WSCNTL_GetInterfaceName(int intNumber
, char *intName
)
517 char buf
[512]; /* Size doesn't matter, something big */
520 /* Open /proc filesystem file for network devices */
521 procfs
= fopen(PROCFS_NETDEV_FILE
, "r");
524 /* If we can't open the file, return an error */
528 /* Omit first two lines, they are only headers */
529 fgets(buf
, sizeof(buf
), procfs
);
530 fgets(buf
, sizeof(buf
), procfs
);
532 for (i
=0; i
<intNumber
; i
++)
534 /* Skip the lines that don't interest us. */
535 fgets(buf
, sizeof(buf
), procfs
);
537 fgets(buf
, sizeof(buf
), procfs
); /* This is the line we want */
540 /* Parse out the line, grabbing only the name of the device
541 to the intName variable
543 The Line comes in like this: (we only care about the device name)
544 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
547 while (isspace(buf
[i
])) /* Skip initial space(s) */
559 if (buf
[i
] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
561 /* This interface could be an alias... */
563 char *dotname
= intName
;
564 *intName
++ = buf
[i
++];
566 while (isdigit(buf
[i
]))
568 *intName
++ = buf
[i
++];
573 /* ... It wasn't, so back up */
588 *intName
++ = buf
[i
++];
598 Helper function for WsControl - This function returns the bytes (octets) transmitted
599 and received for the supplied interface number from the /proc fs.
601 int WSCNTL_GetTransRecvStat(int intNumber
, unsigned long *transBytes
, unsigned long *recvBytes
)
604 char buf
[512], result
[512]; /* Size doesn't matter, something big */
605 int i
, bufPos
, resultPos
;
607 /* Open /proc filesystem file for network devices */
608 procfs
= fopen(PROCFS_NETDEV_FILE
, "r");
611 /* If we can't open the file, return an error */
615 /* Omit first two lines, they are only headers */
616 fgets(buf
, sizeof(buf
), procfs
);
617 fgets(buf
, sizeof(buf
), procfs
);
619 for (i
=0; i
<intNumber
; i
++)
621 /* Skip the lines that don't interest us. */
622 fgets(buf
, sizeof(buf
), procfs
);
624 fgets(buf
, sizeof(buf
), procfs
); /* This is the line we want */
628 /* Parse out the line, grabbing the number of bytes transmitted
629 and received on the interface.
631 The Line comes in like this: (we care about columns 2 and 10)
632 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
635 /* Start at character 0 in the buffer */
638 /* Skip initial space(s) */
639 while (isspace(buf
[bufPos
]))
643 /* Skip the name and its trailing spaces (if any) */
646 if (isspace(buf
[bufPos
]))
649 if (buf
[bufPos
] == ':') /* Could be an alias */
653 while(isdigit (buf
[bufPos
]))
655 if (buf
[bufPos
] != ':')
657 if (buf
[bufPos
] == '\0')
669 while (isspace(buf
[bufPos
]))
673 /* This column (#2) is the number of bytes received. */
675 while (!isspace(buf
[bufPos
]))
677 result
[resultPos
] = buf
[bufPos
];
678 result
[resultPos
+1]='\0';
679 resultPos
++; bufPos
++;
681 *recvBytes
= strtoul (result
, NULL
, 10); /* convert string to unsigned long, using base 10 */
684 /* Skip columns #3 to #9 (Don't need them) */
687 while (isspace(buf
[bufPos
]))
689 while (!isspace(buf
[bufPos
]))
694 /* This column (#10) is the number of bytes transmitted */
695 while (isspace(buf
[bufPos
]))
699 while (!isspace(buf
[bufPos
]))
701 result
[resultPos
] = buf
[bufPos
];
702 result
[resultPos
+1]='\0';
703 resultPos
++; bufPos
++;
705 *transBytes
= strtoul (result
, NULL
, 10); /* convert string to unsigned long, using base 10 */
713 /***********************************************************************
714 * WSARecvEx() (WSOCK32.1107)
716 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
717 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
718 * into the flags parameter when a partial packet is read. This only applies to
719 * sockets using the datagram protocol. This method does not seem to be implemented
720 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
721 * flag when a fragmented packet arrives.
723 INT WINAPI
WSARecvEx(SOCKET s
, char *buf
, INT len
, INT
*flags
)
725 FIXME("(WSARecvEx) partial packet return value not set \n");
726 return recv(s
, buf
, len
, *flags
);
730 /***********************************************************************
731 * WS_s_perror (WSOCK32.1108)
733 void WINAPI
WS_s_perror(LPCSTR message
)
735 FIXME("(%s): stub\n",message
);