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
25 #include <sys/types.h>
28 #include "debugtools.h"
31 #include "wscontrol.h"
33 #include <sys/ioctl.h>
37 #ifdef HAVE_SYS_SOCKIO_H
38 # include <sys/sockio.h>
45 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
48 extern SOCKET WINAPI socket(INT af, INT type, INT protocol);
52 DEFAULT_DEBUG_CHANNEL(winsock);
55 /***********************************************************************
58 * WsControl seems to be an undocumented Win95 function. A lot of
59 * discussion about WsControl can be found on the net, e.g.
60 * Subject: Re: WSOCK32.DLL WsControl Exported Function
61 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
64 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
65 * on observing the behaviour of WsControl with an app in
66 * Windows 98. It is not fully implemented, and there could
67 * be (are?) errors due to incorrect assumptions made.
70 * WsControl returns WSCTL_SUCCESS on success.
71 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
72 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
74 * It doesn't seem to generate errors that can be retrieved by
79 DWORD WINAPI WsControl(DWORD protocoll,
82 LPDWORD pcbRequestInfoLen,
84 LPDWORD pcbResponseInfoLen)
86 /* Get the command structure into a pointer we can use,
88 TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
90 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
91 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
92 pcommand->toi_class, pcommand->toi_type );
98 case WSCNTL_TCPIP_QUERY_INFO:
100 switch (pcommand->toi_id)
103 ENTITY_LIST_ID seems to get number of adapters in the system.
104 (almost like an index to be used when calling other WsControl options)
108 TDIEntityID *baseptr = pResponseInfo;
111 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
112 pcommand->toi_type != INFO_TYPE_PROVIDER)
114 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
115 pcommand->toi_class, pcommand->toi_type);
116 return (WSAEOPNOTSUPP);
119 numInt = WSCNTL_GetInterfaceCount();
122 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
126 if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
128 return (STATUS_BUFFER_TOO_SMALL);
132 memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
134 for (i=0; i<numInt; i++)
136 /* tei_instance is an network interface identifier.
137 I'm not quite sure what the difference is between tei_entity values of
138 CL_NL_ENTITY and IF_ENTITY */
139 baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = i; baseptr++;
140 baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
143 /* Calculate size of out buffer */
144 *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
150 /* ENTITY_TYPE_ID is used to obtain simple information about a
151 network card, such as MAC Address, description, interface type,
152 number of network addresses, etc. */
153 case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
155 if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
157 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
159 * ((ULONG *)pResponseInfo) = IF_MIB;
161 /* Calculate size of out buffer */
162 *pcbResponseInfoLen = sizeof (ULONG);
165 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
167 * ((ULONG *)pResponseInfo) = CL_NL_IP;
169 /* Calculate size of out buffer */
170 *pcbResponseInfoLen = sizeof (ULONG);
173 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
174 pcommand->toi_type == INFO_TYPE_PROVIDER)
176 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
178 /* In this case, we are requesting specific information about a
179 a particular network adapter. (MAC Address, speed, data transmitted/received,
182 IFEntry *IntInfo = (IFEntry *) pResponseInfo;
188 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
190 ERR ("Unable to parse /proc filesystem!\n");
194 /* Get a socket so that we can use ioctl */
195 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
197 ERR ("Error creating socket!\n");
201 /* 0 out return structure first */
202 memset (IntInfo, 0, sizeof(IFEntry));
205 IntInfo->if_index = pcommand->toi_entity.tei_instance;
207 /* MAC Address - Let's try to do this in a cross-platform way... */
208 #if defined(SIOCGIFHWADDR) /* Linux */
209 strcpy(ifInfo.ifr_name, ifName);
210 if (ioctlsocket(sock, SIOCGIFHWADDR, (ULONG*)&ifInfo) < 0)
212 ERR ("Error obtaining MAC Address!\n");
218 /* FIXME: Is it correct to assume size of 6? */
219 memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
220 IntInfo->if_physaddrlen=6;
222 #elif defined(SIOCGENADDR) /* Solaris */
223 if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
225 ERR ("Error obtaining MAC Address!\n");
231 /* FIXME: Is it correct to assume size of 6? */
232 memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
233 IntInfo->if_physaddrlen=6;
236 memset (IntInfo->if_physaddr, 0, 6);
237 ERR ("Unable to determine MAC Address on your platform!\n");
241 /* Interface name and length */
242 strcpy (IntInfo->if_descr, ifName);
243 IntInfo->if_descrlen= strlen (IntInfo->if_descr);
245 /* Obtain bytes transmitted/received for interface */
246 if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
247 &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
249 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
255 /* FIXME: How should the below be properly calculated? ******************/
256 IntInfo->if_type = 0x6; /* Ethernet (?) */
257 IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
258 /************************************************************************/
261 *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
263 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
265 IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
268 /* This case is used to obtain general statistics about the
271 if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
273 return (STATUS_BUFFER_TOO_SMALL);
278 memset(infoStruc, 0, sizeof(IPSNMPInfo));
280 /* Get the number of interfaces */
281 numInt = WSCNTL_GetInterfaceCount();
284 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
288 infoStruc->ipsi_numif = numInt; /* # of interfaces */
289 infoStruc->ipsi_numaddr = numInt; /* # of addresses */
290 infoStruc->ipsi_numroutes = numInt; /* # of routes ~ FIXME - Is this right? */
292 /* FIXME: How should the below be properly calculated? ******************/
293 infoStruc->ipsi_forwarding = 0x0;
294 infoStruc->ipsi_defaultttl = 0x0;
295 infoStruc->ipsi_inreceives = 0x0;
296 infoStruc->ipsi_inhdrerrors = 0x0;
297 infoStruc->ipsi_inaddrerrors = 0x0;
298 infoStruc->ipsi_forwdatagrams = 0x0;
299 infoStruc->ipsi_inunknownprotos = 0x0;
300 infoStruc->ipsi_indiscards = 0x0;
301 infoStruc->ipsi_indelivers = 0x0;
302 infoStruc->ipsi_outrequests = 0x0;
303 infoStruc->ipsi_routingdiscards = 0x0;
304 infoStruc->ipsi_outdiscards = 0x0;
305 infoStruc->ipsi_outnoroutes = 0x0;
306 infoStruc->ipsi_reasmtimeout = 0x0;
307 infoStruc->ipsi_reasmreqds = 0x0;
308 infoStruc->ipsi_reasmoks = 0x0;
309 infoStruc->ipsi_reasmfails = 0x0;
310 infoStruc->ipsi_fragoks = 0x0;
311 infoStruc->ipsi_fragfails = 0x0;
312 infoStruc->ipsi_fragcreates = 0x0;
313 /************************************************************************/
315 /* Calculate size of out buffer */
316 *pcbResponseInfoLen = sizeof(IPSNMPInfo);
322 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
323 pcommand->toi_class, pcommand->toi_type);
325 return (WSAEOPNOTSUPP);
332 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
333 particular network adapter */
334 case IP_MIB_ADDRTABLE_ENTRY_ID:
336 IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
341 if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
343 return (STATUS_BUFFER_TOO_SMALL);
346 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
348 ERR ("Unable to parse /proc filesystem!\n");
353 /* Get a socket so we can use ioctl */
354 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
356 ERR ("Error creating socket!\n");
361 memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
364 baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
367 strcpy (ifInfo.ifr_name, ifName);
368 ifInfo.ifr_addr.sa_family = AF_INET;
369 if (ioctlsocket(sock, SIOCGIFADDR, (ULONG*)&ifInfo) < 0)
371 baseIPInfo->iae_addr = 0x0;
375 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
376 baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
379 /* Broadcast Address */
380 strcpy (ifInfo.ifr_name, ifName);
381 if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
383 baseIPInfo->iae_bcastaddr = 0x0;
387 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
388 baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
392 strcpy(ifInfo.ifr_name, ifName);
393 if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
395 baseIPInfo->iae_mask = 0x0;
399 /* Trying to avoid some compile problems across platforms.
400 (Linux, FreeBSD, Solaris...) */
403 baseIPInfo->iae_mask = 0;
404 ERR ("Unable to determine Netmask on your platform!\n");
406 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
407 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
410 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
411 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
415 /* FIXME: How should the below be properly calculated? ******************/
416 baseIPInfo->iae_reasmsize = 0x0;
417 baseIPInfo->iae_context = 0x0;
418 baseIPInfo->iae_pad = 0x0;
419 /************************************************************************/
421 /* Calculate size of out buffer */
422 *pcbResponseInfoLen = sizeof(IPAddrEntry);
428 FIXME ("Command ID Unknown but used by winipcfg.exe\n");
434 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",
435 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
436 pcommand->toi_class, pcommand->toi_type);
438 return (WSAEOPNOTSUPP);
445 case WSCNTL_TCPIP_ICMP_ECHO:
447 unsigned int addr = *(unsigned int*)pRequestInfo;
449 int timeout= *(unsigned int*)(inbuf+4);
450 short x1 = *(unsigned short*)(inbuf+8);
451 short sendbufsize = *(unsigned short*)(inbuf+10);
452 char x2 = *(unsigned char*)(inbuf+12);
453 char ttl = *(unsigned char*)(inbuf+13);
454 char service = *(unsigned char*)(inbuf+14);
455 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
458 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
464 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
465 protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
467 return (WSAEOPNOTSUPP);
472 return (WSCTL_SUCCESS);
478 Helper function for WsControl - Get count of the number of interfaces
479 by parsing /proc filesystem.
481 int WSCNTL_GetInterfaceCount(void)
484 char buf[512]; /* Size doesn't matter, something big */
488 /* Open /proc filesystem file for network devices */
489 procfs = fopen(PROCFS_NETDEV_FILE, "r");
492 /* If we can't open the file, return an error */
496 /* Omit first two lines, they are only headers */
497 fgets(buf, sizeof buf, procfs);
498 fgets(buf, sizeof buf, procfs);
500 while (fgets(buf, sizeof buf, procfs))
502 /* Each line in the file represents a network interface */
512 Helper function for WsControl - Get name of device from interface number
513 by parsing /proc filesystem.
515 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
518 char buf[512]; /* Size doesn't matter, something big */
521 /* Open /proc filesystem file for network devices */
522 procfs = fopen(PROCFS_NETDEV_FILE, "r");
525 /* If we can't open the file, return an error */
529 /* Omit first two lines, they are only headers */
530 fgets(buf, sizeof(buf), procfs);
531 fgets(buf, sizeof(buf), procfs);
533 for (i=0; i<intNumber; i++)
535 /* Skip the lines that don't interest us. */
536 fgets(buf, sizeof(buf), procfs);
538 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
541 /* Parse out the line, grabbing only the name of the device
542 to the intName variable
544 The Line comes in like this: (we only care about the device name)
545 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
548 while (isspace(buf[i])) /* Skip initial space(s) */
560 if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
562 /* This interface could be an alias... */
564 char *dotname = intName;
565 *intName++ = buf[i++];
567 while (isdigit(buf[i]))
569 *intName++ = buf[i++];
574 /* ... It wasn't, so back up */
589 *intName++ = buf[i++];
599 Helper function for WsControl - This function returns the bytes (octets) transmitted
600 and received for the supplied interface number from the /proc fs.
602 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
605 char buf[512], result[512]; /* Size doesn't matter, something big */
606 int i, bufPos, resultPos;
608 /* Open /proc filesystem file for network devices */
609 procfs = fopen(PROCFS_NETDEV_FILE, "r");
612 /* If we can't open the file, return an error */
616 /* Omit first two lines, they are only headers */
617 fgets(buf, sizeof(buf), procfs);
618 fgets(buf, sizeof(buf), procfs);
620 for (i=0; i<intNumber; i++)
622 /* Skip the lines that don't interest us. */
623 fgets(buf, sizeof(buf), procfs);
625 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
629 /* Parse out the line, grabbing the number of bytes transmitted
630 and received on the interface.
632 The Line comes in like this: (we care about columns 2 and 10)
633 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
636 /* Start at character 0 in the buffer */
639 /* Skip initial space(s) */
640 while (isspace(buf[bufPos]))
644 /* Skip the name and its trailing spaces (if any) */
647 if (isspace(buf[bufPos]))
650 if (buf[bufPos] == ':') /* Could be an alias */
654 while(isdigit (buf[bufPos]))
656 if (buf[bufPos] != ':')
658 if (buf[bufPos] == '\0')
670 while (isspace(buf[bufPos]))
674 /* This column (#2) is the number of bytes received. */
676 while (!isspace(buf[bufPos]))
678 result[resultPos] = buf[bufPos];
679 result[resultPos+1]='\0';
680 resultPos++; bufPos++;
682 *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
685 /* Skip columns #3 to #9 (Don't need them) */
688 while (isspace(buf[bufPos]))
690 while (!isspace(buf[bufPos]))
695 /* This column (#10) is the number of bytes transmitted */
696 while (isspace(buf[bufPos]))
700 while (!isspace(buf[bufPos]))
702 result[resultPos] = buf[bufPos];
703 result[resultPos+1]='\0';
704 resultPos++; bufPos++;
706 *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
714 /***********************************************************************
715 * WSARecvEx() (WSOCK32.1107)
717 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
718 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
719 * into the flags parameter when a partial packet is read. This only applies to
720 * sockets using the datagram protocol. This method does not seem to be implemented
721 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
722 * flag when a fragmented packet arrives.
724 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
726 FIXME("(WSARecvEx) partial packet return value not set \n");
727 return recv(s, buf, len, *flags);
731 /***********************************************************************
732 * WS_s_perror (WSOCK32.1108)
734 void WINAPI WS_s_perror(LPCSTR message)
736 FIXME("(%s): stub\n",message);