2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
12 #include "debugtools.h"
15 #include "wscontrol.h"
17 #include <sys/ioctl.h>
21 #ifdef HAVE_SYS_SOCKIO_H
22 # include <sys/sockio.h>
28 DEFAULT_DEBUG_CHANNEL(winsock
);
30 static INT (WINAPI
*WS2_recv
)(SOCKET s
, char *buf
, INT len
, INT flags
);
32 /***********************************************************************
35 * WsControl seems to be an undocumented Win95 function. A lot of
36 * discussion about WsControl can be found on the net, e.g.
37 * Subject: Re: WSOCK32.DLL WsControl Exported Function
38 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
41 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
42 * on observing the behaviour of WsControl with an app in
43 * Windows 98. It is not fully implemented, and there could
44 * be (are?) errors due to incorrect assumptions made.
47 * WsControl returns WSCTL_SUCCESS on success.
48 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
49 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
51 * It doesn't seem to generate errors that can be retrieved by
56 DWORD WINAPI
WsControl(DWORD protocoll
,
59 LPDWORD pcbRequestInfoLen
,
61 LPDWORD pcbResponseInfoLen
)
63 /* Get the command structure into a pointer we can use,
65 TDIObjectID
*pcommand
= (TDIObjectID
*)pRequestInfo
;
67 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
68 pcommand
->toi_id
, pcommand
->toi_entity
.tei_entity
, pcommand
->toi_entity
.tei_instance
,
69 pcommand
->toi_class
, pcommand
->toi_type
);
75 case WSCNTL_TCPIP_QUERY_INFO
:
77 switch (pcommand
->toi_id
)
80 ENTITY_LIST_ID seems to get number of adapters in the system.
81 (almost like an index to be used when calling other WsControl options)
85 TDIEntityID
*baseptr
= pResponseInfo
;
88 if (pcommand
->toi_class
!= INFO_CLASS_GENERIC
&&
89 pcommand
->toi_type
!= INFO_TYPE_PROVIDER
)
91 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
92 pcommand
->toi_class
, pcommand
->toi_type
);
93 return (WSAEOPNOTSUPP
);
96 numInt
= WSCNTL_GetInterfaceCount();
99 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
103 if (*pcbResponseInfoLen
< sizeof(TDIEntityID
)*(numInt
*2) )
105 return (STATUS_BUFFER_TOO_SMALL
);
109 memset(baseptr
, 0, sizeof(TDIEntityID
)*(numInt
*2));
111 for (i
=0; i
<numInt
; i
++)
113 /* tei_instance is an network interface identifier.
114 I'm not quite sure what the difference is between tei_entity values of
115 CL_NL_ENTITY and IF_ENTITY */
116 baseptr
->tei_entity
= CL_NL_ENTITY
; baseptr
->tei_instance
= i
; baseptr
++;
117 baseptr
->tei_entity
= IF_ENTITY
; baseptr
->tei_instance
= i
; baseptr
++;
120 /* Calculate size of out buffer */
121 *pcbResponseInfoLen
= sizeof(TDIEntityID
)*(numInt
*2);
127 /* ENTITY_TYPE_ID is used to obtain simple information about a
128 network card, such as MAC Address, description, interface type,
129 number of network addresses, etc. */
130 case ENTITY_TYPE_ID
: /* ALSO: IP_MIB_STATS_ID */
132 if (pcommand
->toi_class
== INFO_CLASS_GENERIC
&& pcommand
->toi_type
== INFO_TYPE_PROVIDER
)
134 if (pcommand
->toi_entity
.tei_entity
== IF_ENTITY
)
136 * ((ULONG
*)pResponseInfo
) = IF_MIB
;
138 /* Calculate size of out buffer */
139 *pcbResponseInfoLen
= sizeof (ULONG
);
142 else if (pcommand
->toi_entity
.tei_entity
== CL_NL_ENTITY
)
144 * ((ULONG
*)pResponseInfo
) = CL_NL_IP
;
146 /* Calculate size of out buffer */
147 *pcbResponseInfoLen
= sizeof (ULONG
);
150 else if (pcommand
->toi_class
== INFO_CLASS_PROTOCOL
&&
151 pcommand
->toi_type
== INFO_TYPE_PROVIDER
)
153 if (pcommand
->toi_entity
.tei_entity
== IF_ENTITY
)
155 /* In this case, we are requesting specific information about a
156 a particular network adapter. (MAC Address, speed, data transmitted/received,
159 IFEntry
*IntInfo
= (IFEntry
*) pResponseInfo
;
165 if (!WSCNTL_GetInterfaceName(pcommand
->toi_entity
.tei_instance
, ifName
))
167 ERR ("Unable to parse /proc filesystem!\n");
171 /* Get a socket so that we can use ioctl */
172 if ( (sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) < 0)
174 ERR ("Error creating socket!\n");
178 /* 0 out return structure first */
179 memset (IntInfo
, 0, sizeof(IFEntry
));
182 IntInfo
->if_index
= pcommand
->toi_entity
.tei_instance
;
184 /* MAC Address - Let's try to do this in a cross-platform way... */
185 #if defined(SIOCGIFHWADDR) /* Linux */
186 strcpy(ifInfo
.ifr_name
, ifName
);
187 if (ioctl(sock
, SIOCGIFHWADDR
, &ifInfo
) < 0)
189 ERR ("Error obtaining MAC Address!\n");
195 /* FIXME: Is it correct to assume size of 6? */
196 memcpy(IntInfo
->if_physaddr
, ifInfo
.ifr_hwaddr
.sa_data
, 6);
197 IntInfo
->if_physaddrlen
=6;
199 #elif defined(SIOCGENADDR) /* Solaris */
200 if (ioctl(sock
, SIOCGENADDR
, &ifInfo
) < 0)
202 ERR ("Error obtaining MAC Address!\n");
208 /* FIXME: Is it correct to assume size of 6? */
209 memcpy(IntInfo
->if_physaddr
, ifInfo
.ifr_enaddr
, 6);
210 IntInfo
->if_physaddrlen
=6;
213 memset (IntInfo
->if_physaddr
, 0, 6);
214 ERR ("Unable to determine MAC Address on your platform!\n");
218 /* Interface name and length */
219 strcpy (IntInfo
->if_descr
, ifName
);
220 IntInfo
->if_descrlen
= strlen (IntInfo
->if_descr
);
222 /* Obtain bytes transmitted/received for interface */
223 if ( (WSCNTL_GetTransRecvStat(pcommand
->toi_entity
.tei_instance
,
224 &IntInfo
->if_inoctets
, &IntInfo
->if_outoctets
)) < 0)
226 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
232 /* FIXME: How should the below be properly calculated? ******************/
233 IntInfo
->if_type
= 0x6; /* Ethernet (?) */
234 IntInfo
->if_speed
= 1000000; /* Speed of interface (bits per second?) */
235 /************************************************************************/
238 *pcbResponseInfoLen
= sizeof (IFEntry
) + IntInfo
->if_descrlen
;
240 else if (pcommand
->toi_entity
.tei_entity
== CL_NL_ENTITY
)
242 IPSNMPInfo
*infoStruc
= (IPSNMPInfo
*) pResponseInfo
;
245 /* This case is used to obtain general statistics about the
248 if (*pcbResponseInfoLen
< sizeof(IPSNMPInfo
) )
250 return (STATUS_BUFFER_TOO_SMALL
);
255 memset(infoStruc
, 0, sizeof(IPSNMPInfo
));
257 /* Get the number of interfaces */
258 numInt
= WSCNTL_GetInterfaceCount();
261 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
265 infoStruc
->ipsi_numif
= numInt
; /* # of interfaces */
266 infoStruc
->ipsi_numaddr
= numInt
; /* # of addresses */
267 infoStruc
->ipsi_numroutes
= numInt
; /* # of routes ~ FIXME - Is this right? */
269 /* FIXME: How should the below be properly calculated? ******************/
270 infoStruc
->ipsi_forwarding
= 0x0;
271 infoStruc
->ipsi_defaultttl
= 0x0;
272 infoStruc
->ipsi_inreceives
= 0x0;
273 infoStruc
->ipsi_inhdrerrors
= 0x0;
274 infoStruc
->ipsi_inaddrerrors
= 0x0;
275 infoStruc
->ipsi_forwdatagrams
= 0x0;
276 infoStruc
->ipsi_inunknownprotos
= 0x0;
277 infoStruc
->ipsi_indiscards
= 0x0;
278 infoStruc
->ipsi_indelivers
= 0x0;
279 infoStruc
->ipsi_outrequests
= 0x0;
280 infoStruc
->ipsi_routingdiscards
= 0x0;
281 infoStruc
->ipsi_outdiscards
= 0x0;
282 infoStruc
->ipsi_outnoroutes
= 0x0;
283 infoStruc
->ipsi_reasmtimeout
= 0x0;
284 infoStruc
->ipsi_reasmreqds
= 0x0;
285 infoStruc
->ipsi_reasmoks
= 0x0;
286 infoStruc
->ipsi_reasmfails
= 0x0;
287 infoStruc
->ipsi_fragoks
= 0x0;
288 infoStruc
->ipsi_fragfails
= 0x0;
289 infoStruc
->ipsi_fragcreates
= 0x0;
290 /************************************************************************/
292 /* Calculate size of out buffer */
293 *pcbResponseInfoLen
= sizeof(IPSNMPInfo
);
299 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
300 pcommand
->toi_class
, pcommand
->toi_type
);
302 return (WSAEOPNOTSUPP
);
309 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
310 particular network adapter */
311 case IP_MIB_ADDRTABLE_ENTRY_ID
:
313 IPAddrEntry
*baseIPInfo
= (IPAddrEntry
*) pResponseInfo
;
318 if (*pcbResponseInfoLen
< sizeof(IPAddrEntry
))
320 return (STATUS_BUFFER_TOO_SMALL
);
323 if (!WSCNTL_GetInterfaceName(pcommand
->toi_entity
.tei_instance
, ifName
))
325 ERR ("Unable to parse /proc filesystem!\n");
330 /* Get a socket so we can use ioctl */
331 if ( (sock
= socket (AF_INET
, SOCK_DGRAM
, 0)) < 0)
333 ERR ("Error creating socket!\n");
338 memset(baseIPInfo
, 0, sizeof(IPAddrEntry
) );
341 baseIPInfo
->iae_index
= pcommand
->toi_entity
.tei_instance
;
344 strcpy (ifInfo
.ifr_name
, ifName
);
345 ifInfo
.ifr_addr
.sa_family
= AF_INET
;
346 if (ioctl(sock
, SIOCGIFADDR
, &ifInfo
) < 0)
348 baseIPInfo
->iae_addr
= 0x0;
352 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_addr
;
353 baseIPInfo
->iae_addr
= ipTemp
->sin_addr
.S_un
.S_addr
;
356 /* Broadcast Address */
357 strcpy (ifInfo
.ifr_name
, ifName
);
358 if (ioctl(sock
, SIOCGIFBRDADDR
, &ifInfo
) < 0)
360 baseIPInfo
->iae_bcastaddr
= 0x0;
364 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_broadaddr
;
365 baseIPInfo
->iae_bcastaddr
= ipTemp
->sin_addr
.S_un
.S_addr
;
369 strcpy(ifInfo
.ifr_name
, ifName
);
370 if (ioctl(sock
, SIOCGIFNETMASK
, &ifInfo
) < 0)
372 baseIPInfo
->iae_mask
= 0x0;
376 /* Trying to avoid some compile problems across platforms.
377 (Linux, FreeBSD, Solaris...) */
380 baseIPInfo
->iae_mask
= 0;
381 ERR ("Unable to determine Netmask on your platform!\n");
383 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_addr
;
384 baseIPInfo
->iae_mask
= ipTemp
->sin_addr
.S_un
.S_addr
;
387 struct ws_sockaddr_in
*ipTemp
= (struct ws_sockaddr_in
*)&ifInfo
.ifr_netmask
;
388 baseIPInfo
->iae_mask
= ipTemp
->sin_addr
.S_un
.S_addr
;
392 /* FIXME: How should the below be properly calculated? ******************/
393 baseIPInfo
->iae_reasmsize
= 0x0;
394 baseIPInfo
->iae_context
= 0x0;
395 baseIPInfo
->iae_pad
= 0x0;
396 /************************************************************************/
398 /* Calculate size of out buffer */
399 *pcbResponseInfoLen
= sizeof(IPAddrEntry
);
407 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",
408 pcommand
->toi_id
, pcommand
->toi_entity
.tei_entity
, pcommand
->toi_entity
.tei_instance
,
409 pcommand
->toi_class
, pcommand
->toi_type
);
411 return (WSAEOPNOTSUPP
);
418 case WSCNTL_TCPIP_ICMP_ECHO
:
420 unsigned int addr
= *(unsigned int*)pRequestInfo
;
422 int timeout
= *(unsigned int*)(inbuf
+4);
423 short x1
= *(unsigned short*)(inbuf
+8);
424 short sendbufsize
= *(unsigned short*)(inbuf
+10);
425 char x2
= *(unsigned char*)(inbuf
+12);
426 char ttl
= *(unsigned char*)(inbuf
+13);
427 char service
= *(unsigned char*)(inbuf
+14);
428 char type
= *(unsigned char*)(inbuf
+15); /* 0x2: don't fragment*/
431 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr
);
437 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
438 protocoll
, action
, pRequestInfo
, pcbRequestInfoLen
, pResponseInfo
, pcbResponseInfoLen
);
440 return (WSAEOPNOTSUPP
);
445 return (WSCTL_SUCCESS
);
451 Helper function for WsControl - Get count of the number of interfaces
452 by parsing /proc filesystem.
454 int WSCNTL_GetInterfaceCount(void)
457 char buf
[512]; /* Size doesn't matter, something big */
461 /* Open /proc filesystem file for network devices */
462 procfs
= fopen(PROCFS_NETDEV_FILE
, "r");
465 /* If we can't open the file, return an error */
469 /* Omit first two lines, they are only headers */
470 fgets(buf
, sizeof buf
, procfs
);
471 fgets(buf
, sizeof buf
, procfs
);
473 while (fgets(buf
, sizeof buf
, procfs
))
475 /* Each line in the file represents a network interface */
485 Helper function for WsControl - Get name of device from interface number
486 by parsing /proc filesystem.
488 int WSCNTL_GetInterfaceName(int intNumber
, char *intName
)
491 char buf
[512]; /* Size doesn't matter, something big */
494 /* Open /proc filesystem file for network devices */
495 procfs
= fopen(PROCFS_NETDEV_FILE
, "r");
498 /* If we can't open the file, return an error */
502 /* Omit first two lines, they are only headers */
503 fgets(buf
, sizeof(buf
), procfs
);
504 fgets(buf
, sizeof(buf
), procfs
);
506 for (i
=0; i
<intNumber
; i
++)
508 /* Skip the lines that don't interest us. */
509 fgets(buf
, sizeof(buf
), procfs
);
511 fgets(buf
, sizeof(buf
), procfs
); /* This is the line we want */
514 /* Parse out the line, grabbing only the name of the device
515 to the intName variable
517 The Line comes in like this: (we only care about the device name)
518 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
521 while (isspace(buf
[i
])) /* Skip initial space(s) */
533 if (buf
[i
] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
535 /* This interface could be an alias... */
537 char *dotname
= intName
;
538 *intName
++ = buf
[i
++];
540 while (isdigit(buf
[i
]))
542 *intName
++ = buf
[i
++];
547 /* ... It wasn't, so back up */
562 *intName
++ = buf
[i
++];
572 Helper function for WsControl - This function returns the bytes (octets) transmitted
573 and received for the supplied interface number from the /proc fs.
575 int WSCNTL_GetTransRecvStat(int intNumber
, unsigned long *transBytes
, unsigned long *recvBytes
)
578 char buf
[512], result
[512]; /* Size doesn't matter, something big */
579 int i
, bufPos
, resultPos
;
581 /* Open /proc filesystem file for network devices */
582 procfs
= fopen(PROCFS_NETDEV_FILE
, "r");
585 /* If we can't open the file, return an error */
589 /* Omit first two lines, they are only headers */
590 fgets(buf
, sizeof(buf
), procfs
);
591 fgets(buf
, sizeof(buf
), procfs
);
593 for (i
=0; i
<intNumber
; i
++)
595 /* Skip the lines that don't interest us. */
596 fgets(buf
, sizeof(buf
), procfs
);
598 fgets(buf
, sizeof(buf
), procfs
); /* This is the line we want */
602 /* Parse out the line, grabbing the number of bytes transmitted
603 and received on the interface.
605 The Line comes in like this: (we care about columns 2 and 10)
606 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
609 /* Start at character 0 in the buffer */
612 /* Skip initial space(s) */
613 while (isspace(buf
[bufPos
]))
617 /* Skip the name and its trailing spaces (if any) */
620 if (isspace(buf
[bufPos
]))
623 if (buf
[bufPos
] == ':') /* Could be an alias */
627 while(isdigit (buf
[bufPos
]))
629 if (buf
[bufPos
] != ':')
631 if (buf
[bufPos
] == '\0')
643 while (isspace(buf
[bufPos
]))
647 /* This column (#2) is the number of bytes received. */
649 while (!isspace(buf
[bufPos
]))
651 result
[resultPos
] = buf
[bufPos
];
652 result
[resultPos
+1]='\0';
653 resultPos
++; bufPos
++;
655 *recvBytes
= strtoul (result
, NULL
, 10); /* convert string to unsigned long, using base 10 */
658 /* Skip columns #3 to #9 (Don't need them) */
661 while (isspace(buf
[bufPos
]))
663 while (!isspace(buf
[bufPos
]))
668 /* This column (#10) is the number of bytes transmitted */
669 while (isspace(buf
[bufPos
]))
673 while (!isspace(buf
[bufPos
]))
675 result
[resultPos
] = buf
[bufPos
];
676 result
[resultPos
+1]='\0';
677 resultPos
++; bufPos
++;
679 *transBytes
= strtoul (result
, NULL
, 10); /* convert string to unsigned long, using base 10 */
687 /***********************************************************************
688 * WSARecvEx() (WSOCK32.1107)
690 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
691 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
692 * into the flags parameter when a partial packet is read. This only applies to
693 * sockets using the datagram protocol. This method does not seem to be implemented
694 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
695 * flag when a fragmented packet arrives.
697 INT WINAPI
WSARecvEx(SOCKET s
, char *buf
, INT len
, INT
*flags
)
699 FIXME("(WSARecvEx) partial packet return value not set \n");
700 return WS2_recv(s
, buf
, len
, *flags
);
704 /***********************************************************************
705 * WS_s_perror (WSOCK32.1108)
707 void WINAPI
WS_s_perror(LPCSTR message
)
709 FIXME("(%s): stub\n",message
);
714 /***********************************************************************
717 BOOL WINAPI
WSOCK_LibMain( HINSTANCE inst
, DWORD reason
, LPVOID reserved
)
719 static HMODULE ws2_32
;
722 case DLL_PROCESS_ATTACH
:
723 /* we import ws2_32 by hand, because we don't want to implicitly */
724 /* link to it; otherwise Unix calls like socket() get redirected */
725 /* to ws2_32.dll and this is not what we want. */
727 if (!(ws2_32
= LoadLibraryA( "ws2_32.dll" )))
729 ERR("could not load ws2_32\n" );
732 WS2_recv
= (void *)GetProcAddress( ws2_32
, "recv" );
734 case DLL_PROCESS_DETACH
:
735 FreeLibrary( ws2_32
);