2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
11 #include "debugtools.h"
14 #include "wscontrol.h"
16 #include <sys/ioctl.h>
24 DEFAULT_DEBUG_CHANNEL(winsock);
27 /***********************************************************************
30 * WsControl seems to be an undocumented Win95 function. A lot of
31 * discussion about WsControl can be found on the net, e.g.
32 * Subject: Re: WSOCK32.DLL WsControl Exported Function
33 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
36 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
37 * on observing the behaviour of WsControl with an app in
38 * Windows 98. It is not fully implemented, and there could
39 * be (are?) errors due to incorrect assumptions made.
42 * WsControl returns WSCTL_SUCCESS on success.
43 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
44 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
46 * It doesn't seem to generate errors that can be retrieved by
51 DWORD WINAPI WsControl(DWORD protocoll,
54 LPDWORD pcbRequestInfoLen,
56 LPDWORD pcbResponseInfoLen)
58 /* Get the command structure into a pointer we can use,
60 TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
62 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
63 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
64 pcommand->toi_class, pcommand->toi_type );
70 case WSCNTL_TCPIP_QUERY_INFO:
72 switch (pcommand->toi_id)
75 ENTITY_LIST_ID seems to get number of adapters in the system.
76 (almost like an index to be used when calling other WsControl options)
80 TDIEntityID *baseptr = pResponseInfo;
83 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
84 pcommand->toi_type != INFO_TYPE_PROVIDER)
86 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
87 pcommand->toi_class, pcommand->toi_type);
88 return (WSAEOPNOTSUPP);
91 numInt = WSCNTL_GetInterfaceCount();
94 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
98 if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
100 return (STATUS_BUFFER_TOO_SMALL);
104 memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
106 for (i=0; i<numInt; i++)
108 /* tei_instance is an network interface identifier.
109 I'm not quite sure what the difference is between tei_entity values of
110 CL_NL_ENTITY and IF_ENTITY */
111 baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = i; baseptr++;
112 baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
115 /* Calculate size of out buffer */
116 *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
122 /* ENTITY_TYPE_ID is used to obtain simple information about a
123 network card, such as MAC Address, description, interface type,
124 number of network addresses, etc. */
125 case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
127 if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
129 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
131 * ((ULONG *)pResponseInfo) = IF_MIB;
133 /* Calculate size of out buffer */
134 *pcbResponseInfoLen = sizeof (ULONG);
137 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
139 * ((ULONG *)pResponseInfo) = CL_NL_IP;
141 /* Calculate size of out buffer */
142 *pcbResponseInfoLen = sizeof (ULONG);
145 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
146 pcommand->toi_type == INFO_TYPE_PROVIDER)
148 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
150 /* In this case, we are requesting specific information about a
151 a particular network adapter. (MAC Address, speed, data transmitted/received,
154 IFEntry *IntInfo = (IFEntry *) pResponseInfo;
160 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
162 ERR ("Unable to parse /proc filesystem!\n");
166 /* Get a socket so that we can use ioctl */
167 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
169 ERR ("Error creating socket!\n");
173 /* 0 out return structure first */
174 memset (IntInfo, 0, sizeof(IFEntry));
177 IntInfo->if_index = pcommand->toi_entity.tei_instance;
180 strcpy(ifInfo.ifr_name, ifName);
181 if (ioctl(sock, SIOCGIFHWADDR, &ifInfo) < 0)
183 ERR ("Error obtaining MAC Address!\n");
189 /* FIXME: Is it correct to assume size of 6? */
190 memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
191 IntInfo->if_physaddrlen=6;
194 /* Interface name and length */
195 strcpy (IntInfo->if_descr, ifName);
196 IntInfo->if_descrlen= strlen (IntInfo->if_descr);
198 /* Obtain bytes transmitted/received for interface */
199 if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
200 &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
202 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
208 /* FIXME: How should the below be properly calculated? ******************/
209 IntInfo->if_type = 0x6; /* Ethernet (?) */
210 IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
211 /************************************************************************/
214 *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
216 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
218 IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
221 /* This case is used to obtain general statistics about the
224 if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
226 return (STATUS_BUFFER_TOO_SMALL);
231 memset(infoStruc, 0, sizeof(IPSNMPInfo));
233 /* Get the number of interfaces */
234 numInt = WSCNTL_GetInterfaceCount();
237 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
241 infoStruc->ipsi_numif = numInt; /* # of interfaces */
242 infoStruc->ipsi_numaddr = numInt; /* # of addresses */
243 infoStruc->ipsi_numroutes = numInt; /* # of routes ~ FIXME - Is this right? */
245 /* FIXME: How should the below be properly calculated? ******************/
246 infoStruc->ipsi_forwarding = 0x0;
247 infoStruc->ipsi_defaultttl = 0x0;
248 infoStruc->ipsi_inreceives = 0x0;
249 infoStruc->ipsi_inhdrerrors = 0x0;
250 infoStruc->ipsi_inaddrerrors = 0x0;
251 infoStruc->ipsi_forwdatagrams = 0x0;
252 infoStruc->ipsi_inunknownprotos = 0x0;
253 infoStruc->ipsi_indiscards = 0x0;
254 infoStruc->ipsi_indelivers = 0x0;
255 infoStruc->ipsi_outrequests = 0x0;
256 infoStruc->ipsi_routingdiscards = 0x0;
257 infoStruc->ipsi_outdiscards = 0x0;
258 infoStruc->ipsi_outnoroutes = 0x0;
259 infoStruc->ipsi_reasmtimeout = 0x0;
260 infoStruc->ipsi_reasmreqds = 0x0;
261 infoStruc->ipsi_reasmoks = 0x0;
262 infoStruc->ipsi_reasmfails = 0x0;
263 infoStruc->ipsi_fragoks = 0x0;
264 infoStruc->ipsi_fragfails = 0x0;
265 infoStruc->ipsi_fragcreates = 0x0;
266 /************************************************************************/
268 /* Calculate size of out buffer */
269 *pcbResponseInfoLen = sizeof(IPSNMPInfo);
275 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
276 pcommand->toi_class, pcommand->toi_type);
278 return (WSAEOPNOTSUPP);
285 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
286 particular network adapter */
287 case IP_MIB_ADDRTABLE_ENTRY_ID:
289 IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
294 if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
296 return (STATUS_BUFFER_TOO_SMALL);
299 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
301 ERR ("Unable to parse /proc filesystem!\n");
306 /* Get a socket so we can use ioctl */
307 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
309 ERR ("Error creating socket!\n");
314 memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
317 baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
320 strcpy (ifInfo.ifr_name, ifName);
321 ifInfo.ifr_addr.sa_family = AF_INET;
322 if (ioctl(sock, SIOCGIFADDR, &ifInfo) < 0)
324 baseIPInfo->iae_addr = 0x0;
328 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
329 baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
332 /* Broadcast Address */
333 strcpy (ifInfo.ifr_name, ifName);
334 if (ioctl(sock, SIOCGIFBRDADDR, &ifInfo) < 0)
336 baseIPInfo->iae_bcastaddr = 0x0;
340 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
341 baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
345 strcpy(ifInfo.ifr_name, ifName);
346 if (ioctl(sock, SIOCGIFNETMASK, &ifInfo) < 0)
348 baseIPInfo->iae_mask = 0x0;
352 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
353 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
356 /* FIXME: How should the below be properly calculated? ******************/
357 baseIPInfo->iae_reasmsize = 0x0;
358 baseIPInfo->iae_context = 0x0;
359 baseIPInfo->iae_pad = 0x0;
360 /************************************************************************/
362 /* Calculate size of out buffer */
363 *pcbResponseInfoLen = sizeof(IPAddrEntry);
371 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",
372 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
373 pcommand->toi_class, pcommand->toi_type);
375 return (WSAEOPNOTSUPP);
382 case WSCNTL_TCPIP_ICMP_ECHO:
384 unsigned int addr = *(unsigned int*)pRequestInfo;
386 int timeout= *(unsigned int*)(inbuf+4);
387 short x1 = *(unsigned short*)(inbuf+8);
388 short sendbufsize = *(unsigned short*)(inbuf+10);
389 char x2 = *(unsigned char*)(inbuf+12);
390 char ttl = *(unsigned char*)(inbuf+13);
391 char service = *(unsigned char*)(inbuf+14);
392 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
395 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
401 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
402 protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
404 return (WSAEOPNOTSUPP);
409 return (WSCTL_SUCCESS);
415 Helper function for WsControl - Get count of the number of interfaces
416 by parsing /proc filesystem.
418 int WSCNTL_GetInterfaceCount(void)
421 char buf[512]; /* Size doesn't matter, something big */
425 /* Open /proc filesystem file for network devices */
426 procfs = fopen(PROCFS_NETDEV_FILE, "r");
429 /* If we can't open the file, return an error */
433 /* Omit first two lines, they are only headers */
434 fgets(buf, sizeof buf, procfs);
435 fgets(buf, sizeof buf, procfs);
437 while (fgets(buf, sizeof buf, procfs))
439 /* Each line in the file represents a network interface */
449 Helper function for WsControl - Get name of device from interface number
450 by parsing /proc filesystem.
452 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
455 char buf[512]; /* Size doesn't matter, something big */
458 /* Open /proc filesystem file for network devices */
459 procfs = fopen(PROCFS_NETDEV_FILE, "r");
462 /* If we can't open the file, return an error */
466 /* Omit first two lines, they are only headers */
467 fgets(buf, sizeof(buf), procfs);
468 fgets(buf, sizeof(buf), procfs);
470 for (i=0; i<intNumber; i++)
472 /* Skip the lines that don't interest us. */
473 fgets(buf, sizeof(buf), procfs);
475 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
478 /* Parse out the line, grabbing only the name of the device
479 to the intName variable
481 The Line comes in like this: (we only care about the device name)
482 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
485 while (isspace(buf[i])) /* Skip initial space(s) */
497 if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
499 /* This interface could be an alias... */
501 char *dotname = intName;
502 *intName++ = buf[i++];
504 while (isdigit(buf[i]))
506 *intName++ = buf[i++];
511 /* ... It wasn't, so back up */
526 *intName++ = buf[i++];
536 Helper function for WsControl - This function returns the bytes (octets) transmitted
537 and received for the supplied interface number from the /proc fs.
539 int WSCNTL_GetTransRecvStat(int intNumber, ulong *transBytes, ulong *recvBytes)
542 char buf[512], result[512]; /* Size doesn't matter, something big */
543 int i, bufPos, resultPos;
545 /* Open /proc filesystem file for network devices */
546 procfs = fopen(PROCFS_NETDEV_FILE, "r");
549 /* If we can't open the file, return an error */
553 /* Omit first two lines, they are only headers */
554 fgets(buf, sizeof(buf), procfs);
555 fgets(buf, sizeof(buf), procfs);
557 for (i=0; i<intNumber; i++)
559 /* Skip the lines that don't interest us. */
560 fgets(buf, sizeof(buf), procfs);
562 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
566 /* Parse out the line, grabbing the number of bytes transmitted
567 and received on the interface.
569 The Line comes in like this: (we care about columns 2 and 10)
570 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
573 /* Start at character 0 in the buffer */
576 /* Skip initial space(s) */
577 while (isspace(buf[bufPos]))
581 /* Skip the name and its trailing spaces (if any) */
584 if (isspace(buf[bufPos]))
587 if (buf[bufPos] == ':') /* Could be an alias */
591 while(isdigit (buf[bufPos]))
593 if (buf[bufPos] != ':')
595 if (buf[bufPos] == '\0')
607 while (isspace(buf[bufPos]))
611 /* This column (#2) is the number of bytes received. */
613 while (!isspace(buf[bufPos]))
615 result[resultPos] = buf[bufPos];
616 result[resultPos+1]='\0';
617 resultPos++; bufPos++;
619 *recvBytes = strtoul (result, NULL, 10); /* convert string to ulong, using base 10 */
622 /* Skip columns #3 to #9 (Don't need them) */
625 while (isspace(buf[bufPos]))
627 while (!isspace(buf[bufPos]))
632 /* This column (#10) is the number of bytes transmitted */
633 while (isspace(buf[bufPos]))
637 while (!isspace(buf[bufPos]))
639 result[resultPos] = buf[bufPos];
640 result[resultPos+1]='\0';
641 resultPos++; bufPos++;
643 *transBytes = strtoul (result, NULL, 10); /* convert string to ulong, using base 10 */
653 /***********************************************************************
654 * WS_s_perror (WSOCK32.1108)
656 void WINAPI WS_s_perror(LPCSTR message)
658 FIXME("(%s): stub\n",message);