iSelectedImage is allowed to be 0.
[wine] / dlls / wsock32 / socket.c
1 /*
2  * WSOCK32 specific functions
3  *
4  * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5  * Copyright (C) 2003 Juan Lang.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22
23 #include "config.h"
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wine/debug.h"
29 #include "winsock2.h"
30 #include "winnt.h"
31 #include "wscontrol.h"
32 #include "iphlpapi.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
35
36 /* internal remapper function for the IP_ constants */
37 static INT _remap_optname(INT level, INT optname)
38 {
39   TRACE("level=%d, optname=%d\n", level, optname);
40   if (level == IPPROTO_IP) {
41     switch (optname) {       /***** from value *****/
42       case 2: return 9;      /* IP_MULTICAST_IF    */
43       case 3: return 10;     /* IP_MULTICAST_TTL   */
44       case 4: return 11;     /* IP_MULTICAST_LOOP  */
45       case 5: return 12;     /* IP_ADD_MEMBERSHIP  */
46       case 6: return 13;     /* IP_DROP_MEMBERSHIP */
47       case 7: return 4;      /* IP_TTL             */
48       case 8: return 3;      /* IP_TOS             */
49       case 9: return 14;     /* IP_DONTFRAGMENT    */
50       default: FIXME("Unknown optname %d, can't remap!\n", optname); return optname; 
51     }
52   } else {
53     /* don't need to do anything */
54     return optname;
55   }
56 }
57
58 /***********************************************************************
59  *              setsockopt              (WSOCK32.21)
60  *
61  * We have these forwarders because, for reasons unknown to us mere mortals,
62  * the values of the IP_ constants changed between winsock.h and winsock2.h.
63  * So, we need to remap them here.
64  */
65 INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
66 {
67   return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
68 }
69
70 /***********************************************************************
71  *              getsockopt              (WSOCK32.7)
72  */
73 INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
74 {
75   return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
76 }
77
78 /***********************************************************************
79  *              WsControl (WSOCK32.1001)
80  *
81  * WsControl seems to be an undocumented Win95 function. A lot of
82  * discussion about WsControl can be found on the net, e.g.
83  * Subject:      Re: WSOCK32.DLL WsControl Exported Function
84  * From:         "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
85  * Date:         1997/08/17
86  *
87  * The WSCNTL_TCPIP_QUERY_INFO option is partially implemented based
88  * on observing the behaviour of WsControl with an app in
89  * Windows 98.  It is not fully implemented, and there could
90  * be (are?) errors due to incorrect assumptions made.
91  *
92  *
93  * WsControl returns WSCTL_SUCCESS on success.
94  * ERROR_LOCK_VIOLATION is returned if the output buffer length
95  * (*pcbResponseInfoLen) is too small.  This is an unusual error code, but
96  * it matches Win98's behavior.  Other errors come from winerror.h, not from
97  * winsock.h.  Again, this is to match Win98 behavior.
98  *
99  */
100
101 DWORD WINAPI WsControl(DWORD protocol,
102                        DWORD action,
103                        LPVOID pRequestInfo,
104                        LPDWORD pcbRequestInfoLen,
105                        LPVOID pResponseInfo,
106                        LPDWORD pcbResponseInfoLen)
107 {
108
109    /* Get the command structure into a pointer we can use,
110       rather than void */
111    TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
112
113    /* validate input parameters.  Error codes are from winerror.h, not from
114     * winsock.h.  pcbResponseInfoLen is apparently allowed to be NULL for some
115     * commands, since winipcfg.exe fails if we ensure it's non-NULL in every
116     * case.
117     */
118    if (protocol != IPPROTO_TCP) return ERROR_INVALID_PARAMETER;
119    if (!pcommand) return ERROR_INVALID_PARAMETER;
120    if (!pcbRequestInfoLen) return ERROR_INVALID_ACCESS;
121    if (*pcbRequestInfoLen < sizeof(TDIObjectID)) return ERROR_INVALID_ACCESS;
122    if (!pResponseInfo) return ERROR_INVALID_PARAMETER;
123    if (pcommand->toi_type != INFO_TYPE_PROVIDER) return ERROR_INVALID_PARAMETER;
124
125    TRACE ("   WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
126       pcommand->toi_id, pcommand->toi_entity.tei_entity,
127       pcommand->toi_entity.tei_instance,
128       pcommand->toi_class, pcommand->toi_type );
129
130    switch (action)
131    {
132    case WSCNTL_TCPIP_QUERY_INFO:
133    {
134       if (pcommand->toi_class != INFO_CLASS_GENERIC &&
135        pcommand->toi_class != INFO_CLASS_PROTOCOL)
136       {
137          ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO\n",
138           pcommand->toi_class);
139          return ERROR_BAD_ENVIRONMENT;
140       }
141
142       switch (pcommand->toi_id)
143       {
144          /* ENTITY_LIST_ID gets the list of "entity IDs", where an entity
145             may represent an interface, or a datagram service, or address
146             translation, or other fun things.  Typically an entity ID represents
147             a class of service, which is further queried for what type it is.
148             Different types will then have more specific queries defined.
149          */
150          case ENTITY_LIST_ID:
151          {
152             TDIEntityID *baseptr = (TDIEntityID *)pResponseInfo;
153             DWORD numInt, i, ifTable, spaceNeeded;
154             PMIB_IFTABLE table;
155
156             if (!pcbResponseInfoLen)
157                return ERROR_BAD_ENVIRONMENT;
158             if (pcommand->toi_class != INFO_CLASS_GENERIC)
159             {
160                FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx\n",
161                     pcommand->toi_class);
162                return (ERROR_BAD_ENVIRONMENT);
163             }
164
165             GetNumberOfInterfaces(&numInt);
166             spaceNeeded = sizeof(TDIEntityID) * (numInt * 2 + 3);
167
168             if (*pcbResponseInfoLen < spaceNeeded)
169                return (ERROR_LOCK_VIOLATION);
170
171             ifTable = 0;
172             GetIfTable(NULL, &ifTable, FALSE);
173             table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ifTable );
174             if (!table)
175                return ERROR_NOT_ENOUGH_MEMORY;
176             GetIfTable(table, &ifTable, FALSE);
177
178             spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
179             if (*pcbResponseInfoLen < spaceNeeded)
180             {
181                HeapFree( GetProcessHeap(), 0, table );
182                return ERROR_LOCK_VIOLATION;
183             }
184
185             memset(baseptr, 0, spaceNeeded);
186
187             for (i = 0; i < table->dwNumEntries; i++)
188             {
189                /* Return IF_GENERIC and CL_NL_ENTITY on every interface, and
190                 * AT_ENTITY, CL_TL_ENTITY, and CO_TL_ENTITY on the first
191                 * interface.  MS returns them only on the loopback interface,
192                 * but it doesn't seem to matter.
193                 */
194                if (i == 0)
195                {
196                   baseptr->tei_entity = CO_TL_ENTITY;
197                   baseptr->tei_instance = table->table[i].dwIndex;
198                   baseptr++;
199                   baseptr->tei_entity = CL_TL_ENTITY;
200                   baseptr->tei_instance = table->table[i].dwIndex;
201                   baseptr++;
202                   baseptr->tei_entity = AT_ENTITY;
203                   baseptr->tei_instance = table->table[i].dwIndex;
204                   baseptr++;
205                }
206                baseptr->tei_entity = CL_NL_ENTITY;
207                baseptr->tei_instance = table->table[i].dwIndex;
208                baseptr++;
209                baseptr->tei_entity = IF_GENERIC;
210                baseptr->tei_instance = table->table[i].dwIndex;
211                baseptr++;
212             }
213
214             *pcbResponseInfoLen = spaceNeeded;
215             HeapFree( GetProcessHeap(), 0, table );
216             break;
217          }
218
219          /* Returns MIB-II statistics for an interface */
220          case ENTITY_TYPE_ID:
221             switch (pcommand->toi_entity.tei_entity)
222             {
223             case IF_GENERIC:
224                if (pcommand->toi_class == INFO_CLASS_GENERIC)
225                {
226                   if (!pcbResponseInfoLen)
227                      return ERROR_BAD_ENVIRONMENT;
228                   *((ULONG *)pResponseInfo) = IF_MIB;
229                   *pcbResponseInfoLen = sizeof(ULONG);
230                }
231                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
232                {
233                   MIB_IFROW row;
234                   DWORD index = pcommand->toi_entity.tei_instance, ret;
235                   DWORD size = sizeof(row) - sizeof(row.wszName) -
236                    sizeof(row.bDescr);
237
238                   if (!pcbResponseInfoLen)
239                      return ERROR_BAD_ENVIRONMENT;
240                   if (*pcbResponseInfoLen < size)
241                      return (ERROR_LOCK_VIOLATION);
242                   row.dwIndex = index;
243                   ret = GetIfEntry(&row);
244                   if (ret != NO_ERROR)
245                   {
246                      /* FIXME: Win98's arp.exe insists on querying index 1 for
247                       * its MIB-II stats, regardless of the tei_instances
248                       * returned in the ENTITY_LIST query above.  If the query
249                       * fails, arp.exe fails.  So, I do this hack return value
250                       * if index is 1 and the query failed just to get arp.exe
251                       * to continue.
252                       */
253                      if (index == 1)
254                         return NO_ERROR;
255                      ERR ("Error retrieving data for interface index %lu\n",
256                       index);
257                      return ret;
258                   }
259                   size = sizeof(row) - sizeof(row.wszName) -
260                    sizeof(row.bDescr) + row.dwDescrLen;
261                   if (*pcbResponseInfoLen < size)
262                      return (ERROR_LOCK_VIOLATION);
263                   memcpy(pResponseInfo, &row.dwIndex, size);
264                   *pcbResponseInfoLen = size;
265                }
266                break;
267
268             /* Returns address-translation related data.  In our case, this is
269              * ARP.
270              */
271             case AT_ENTITY:
272                if (pcommand->toi_class == INFO_CLASS_GENERIC)
273                {
274                   if (!pcbResponseInfoLen)
275                      return ERROR_BAD_ENVIRONMENT;
276                   *((ULONG *)pResponseInfo) = AT_ARP;
277                   *pcbResponseInfoLen = sizeof(ULONG);
278                }
279                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
280                {
281                   PMIB_IPNETTABLE table;
282                   DWORD size;
283                   PULONG output = (PULONG)pResponseInfo;
284
285                   if (!pcbResponseInfoLen)
286                      return ERROR_BAD_ENVIRONMENT;
287                   if (*pcbResponseInfoLen < sizeof(ULONG) * 2)
288                      return (ERROR_LOCK_VIOLATION);
289                   GetIpNetTable(NULL, &size, FALSE);
290                   table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
291                   if (!table)
292                      return ERROR_NOT_ENOUGH_MEMORY;
293                   GetIpNetTable(table, &size, FALSE);
294                   /* FIXME: I don't understand the meaning of the ARP output
295                    * very well, but it seems to indicate how many ARP entries
296                    * exist.  I don't know whether this should reflect the
297                    * number per interface, as I'm only testing with a single
298                    * interface.  So, I lie and say all ARP entries exist on
299                    * a single interface--the first one that appears in the
300                    * ARP table.
301                    */
302                   *(output++) = table->dwNumEntries;
303                   *output = table->table[0].dwIndex;
304                   HeapFree( GetProcessHeap(), 0, table );
305                   *pcbResponseInfoLen = sizeof(ULONG) * 2;
306                }
307                break;
308
309             /* Returns connectionless network layer statistics--in our case,
310              * this is IP.
311              */
312             case CL_NL_ENTITY:
313                if (pcommand->toi_class == INFO_CLASS_GENERIC)
314                {
315                   if (!pcbResponseInfoLen)
316                      return ERROR_BAD_ENVIRONMENT;
317                   *((ULONG *)pResponseInfo) = CL_NL_IP;
318                   *pcbResponseInfoLen = sizeof(ULONG);
319                }
320                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
321                {
322                   if (!pcbResponseInfoLen)
323                      return ERROR_BAD_ENVIRONMENT;
324                   if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
325                      return ERROR_LOCK_VIOLATION;
326                   GetIpStatistics((PMIB_IPSTATS)pResponseInfo);
327
328                   *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
329                }
330                break;
331
332             /* Returns connectionless transport layer statistics--in our case,
333              * this is UDP.
334              */
335             case CL_TL_ENTITY:
336                if (pcommand->toi_class == INFO_CLASS_GENERIC)
337                {
338                   if (!pcbResponseInfoLen)
339                      return ERROR_BAD_ENVIRONMENT;
340                   *((ULONG *)pResponseInfo) = CL_TL_UDP;
341                   *pcbResponseInfoLen = sizeof(ULONG);
342                }
343                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
344                {
345                   if (!pcbResponseInfoLen)
346                      return ERROR_BAD_ENVIRONMENT;
347                   if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS))
348                      return ERROR_LOCK_VIOLATION;
349                   GetUdpStatistics((PMIB_UDPSTATS)pResponseInfo);
350                   *pcbResponseInfoLen = sizeof(MIB_UDPSTATS);
351                }
352                break;
353
354             /* Returns connection-oriented transport layer statistics--in our
355              * case, this is TCP.
356              */
357             case CO_TL_ENTITY:
358                if (pcommand->toi_class == INFO_CLASS_GENERIC)
359                {
360                   if (!pcbResponseInfoLen)
361                      return ERROR_BAD_ENVIRONMENT;
362                   *((ULONG *)pResponseInfo) = CO_TL_TCP;
363                   *pcbResponseInfoLen = sizeof(ULONG);
364                }
365                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
366                {
367                   if (!pcbResponseInfoLen)
368                      return ERROR_BAD_ENVIRONMENT;
369                   if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS))
370                      return ERROR_LOCK_VIOLATION;
371                   GetTcpStatistics((PMIB_TCPSTATS)pResponseInfo);
372                   *pcbResponseInfoLen = sizeof(MIB_TCPSTATS);
373                }
374                break;
375
376             default:
377                ERR("Unknown entity %ld for ENTITY_TYPE_ID query\n",
378                 pcommand->toi_entity.tei_entity);
379          }
380          break;
381
382          /* This call returns the IP address, subnet mask, and broadcast
383           * address for an interface.  If there are multiple IP addresses for
384           * the interface with the given index, returns the "first" one.
385           */
386          case IP_MIB_ADDRTABLE_ENTRY_ID:
387          {
388             DWORD index = pcommand->toi_entity.tei_instance;
389             PMIB_IPADDRROW baseIPInfo = (PMIB_IPADDRROW) pResponseInfo;
390             PMIB_IPADDRTABLE table;
391             DWORD tableSize, i;
392
393             if (!pcbResponseInfoLen)
394                return ERROR_BAD_ENVIRONMENT;
395             if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
396                return (ERROR_LOCK_VIOLATION);
397
398             /* get entire table, because there isn't an exported function that
399                gets just one entry. */
400             tableSize = 0;
401             GetIpAddrTable(NULL, &tableSize, FALSE);
402             table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, tableSize );
403             if (!table)
404                return ERROR_NOT_ENOUGH_MEMORY;
405             GetIpAddrTable(table, &tableSize, FALSE);
406             for (i = 0; i < table->dwNumEntries; i++)
407             {
408                if (table->table[i].dwIndex == index)
409                {
410                   TRACE("Found IP info for tei_instance 0x%lx:\n", index);
411                   TRACE("IP 0x%08lx, mask 0x%08lx\n", table->table[i].dwAddr,
412                    table->table[i].dwMask);
413                   memcpy(baseIPInfo, &table->table[i], sizeof(MIB_IPADDRROW));
414                   break;
415                }
416             }
417             HeapFree( GetProcessHeap(), 0, table );
418
419             *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
420             break;
421          }
422
423          case IP_MIB_TABLE_ENTRY_ID:
424          {
425             switch (pcommand->toi_entity.tei_entity)
426             {
427             /* This call returns the routing table.
428              * No official documentation found, even the name of the command is unknown.
429              * Work is based on
430              * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
431              * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
432              * pcommand->toi_entity.tei_instance seems to be the interface number
433              * but route.exe outputs only the information for the last interface
434              * if only the routes for the pcommand->toi_entity.tei_instance
435              * interface are returned. */
436                case CL_NL_ENTITY:
437                {
438                   DWORD routeTableSize, numRoutes, ndx, ret;
439                   PMIB_IPFORWARDTABLE table;
440                   IPRouteEntry *winRouteTable  = (IPRouteEntry *) pResponseInfo;
441
442                   if (!pcbResponseInfoLen)
443                      return ERROR_BAD_ENVIRONMENT;
444                   GetIpForwardTable(NULL, &routeTableSize, FALSE);
445                   numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE),
446                    0) / sizeof(MIB_IPFORWARDROW) + 1;
447                   if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
448                      return (ERROR_LOCK_VIOLATION);
449                   table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, routeTableSize );
450                   if (!table)
451                      return ERROR_NOT_ENOUGH_MEMORY;
452                   ret = GetIpForwardTable(table, &routeTableSize, FALSE);
453                   if (ret != NO_ERROR) {
454                      HeapFree( GetProcessHeap(), 0, table );
455                      return ret;
456                   }
457
458                   memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
459                   for (ndx = 0; ndx < table->dwNumEntries; ndx++)
460                   {
461                      winRouteTable->ire_addr = table->table[ndx].dwForwardDest;
462                      winRouteTable->ire_index =
463                       table->table[ndx].dwForwardIfIndex;
464                      winRouteTable->ire_metric =
465                       table->table[ndx].dwForwardMetric1;
466                      /* winRouteTable->ire_option4 =
467                      winRouteTable->ire_option5 =
468                      winRouteTable->ire_option6 = */
469                      winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop;
470                      /* winRouteTable->ire_option8 =
471                      winRouteTable->ire_option9 =
472                      winRouteTable->ire_option10 = */
473                      winRouteTable->ire_mask = table->table[ndx].dwForwardMask;
474                      /* winRouteTable->ire_option12 = */
475                      winRouteTable++;
476                   }
477
478                   /* calculate the length of the data in the output buffer */
479                   *pcbResponseInfoLen = sizeof(IPRouteEntry) *
480                    table->dwNumEntries;
481
482                   HeapFree( GetProcessHeap(), 0, table );
483                }
484                break;
485
486                case AT_ARP:
487                {
488                   DWORD arpTableSize, numEntries, ret;
489                   PMIB_IPNETTABLE table;
490
491                   if (!pcbResponseInfoLen)
492                      return ERROR_BAD_ENVIRONMENT;
493                   GetIpNetTable(NULL, &arpTableSize, FALSE);
494                   numEntries = min(arpTableSize - sizeof(MIB_IPNETTABLE),
495                    0) / sizeof(MIB_IPNETROW) + 1;
496                   if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * numEntries)
497                      return (ERROR_LOCK_VIOLATION);
498                   table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, arpTableSize );
499                   if (!table)
500                      return ERROR_NOT_ENOUGH_MEMORY;
501                   ret = GetIpNetTable(table, &arpTableSize, FALSE);
502                   if (ret != NO_ERROR) {
503                      HeapFree( GetProcessHeap(), 0, table );
504                      return ret;
505                   }
506                   if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) *
507                    table->dwNumEntries)
508                   {
509                      HeapFree( GetProcessHeap(), 0, table );
510                      return ERROR_LOCK_VIOLATION;
511                   }
512                   memcpy(pResponseInfo, table->table, sizeof(MIB_IPNETROW) *
513                    table->dwNumEntries);
514
515                   /* calculate the length of the data in the output buffer */
516                   *pcbResponseInfoLen = sizeof(MIB_IPNETROW) *
517                    table->dwNumEntries;
518
519                   HeapFree( GetProcessHeap(), 0, table );
520                }
521                break;
522
523                case CO_TL_ENTITY:
524                {
525                   DWORD tcpTableSize, numEntries, ret;
526                   PMIB_TCPTABLE table;
527                   DWORD i;
528
529                   if (!pcbResponseInfoLen)
530                      return ERROR_BAD_ENVIRONMENT;
531                   GetTcpTable(NULL, &tcpTableSize, FALSE);
532                   numEntries = min(tcpTableSize - sizeof(MIB_TCPTABLE),
533                    0) / sizeof(MIB_TCPROW) + 1;
534                   if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * numEntries)
535                      return (ERROR_LOCK_VIOLATION);
536                   table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, tcpTableSize );
537                   if (!table)
538                      return ERROR_NOT_ENOUGH_MEMORY;
539                   ret = GetTcpTable(table, &tcpTableSize, FALSE);
540                   if (ret != NO_ERROR) {
541                      HeapFree( GetProcessHeap(), 0, table );
542                      return ret;
543                   }
544                   if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) *
545                    table->dwNumEntries)
546                   {
547                      HeapFree( GetProcessHeap(), 0, table );
548                      return ERROR_LOCK_VIOLATION;
549                   }
550                   for (i = 0; i < table->dwNumEntries; i++)
551                   {
552                      USHORT sPort;
553
554                      sPort = ntohs((USHORT)table->table[i].dwLocalPort);
555                      table->table[i].dwLocalPort = (DWORD)sPort;
556                      sPort = ntohs((USHORT)table->table[i].dwRemotePort);
557                      table->table[i].dwRemotePort = (DWORD)sPort;
558                   }
559                   memcpy(pResponseInfo, table->table, sizeof(MIB_TCPROW) *
560                    table->dwNumEntries);
561
562                   /* calculate the length of the data in the output buffer */
563                   *pcbResponseInfoLen = sizeof(MIB_TCPROW) *
564                    table->dwNumEntries;
565
566                   HeapFree( GetProcessHeap(), 0, table );
567                }
568                break;
569
570                default:
571                {
572                   FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
573                      pcommand->toi_id, pcommand->toi_entity.tei_entity,
574                      pcommand->toi_entity.tei_instance, pcommand->toi_class);
575
576                   return (ERROR_BAD_ENVIRONMENT);
577                }
578             }
579          }
580          break;
581
582
583          default:
584          {
585             FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
586                pcommand->toi_id, pcommand->toi_entity.tei_entity,
587                pcommand->toi_entity.tei_instance, pcommand->toi_class);
588
589             return (ERROR_BAD_ENVIRONMENT);
590          }
591       }
592
593       break;
594    }
595
596    case WSCNTL_TCPIP_ICMP_ECHO:
597    {
598       unsigned int addr = *(unsigned int*)pRequestInfo;
599 #if 0
600          int timeout= *(unsigned int*)(inbuf+4);
601          short x1 = *(unsigned short*)(inbuf+8);
602          short sendbufsize = *(unsigned short*)(inbuf+10);
603          char x2 = *(unsigned char*)(inbuf+12);
604          char ttl = *(unsigned char*)(inbuf+13);
605          char service = *(unsigned char*)(inbuf+14);
606          char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
607 #endif
608
609       FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
610       break;
611    }
612
613    default:
614       FIXME("Protocol Not Supported -> protocol=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
615        protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
616
617       return (WSAEOPNOTSUPP);
618
619    }
620
621    return (WSCTL_SUCCESS);
622 }
623
624
625
626 /***********************************************************************
627  *              WSARecvEx                       (WSOCK32.1107)
628  *
629  * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
630  * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
631  * into the flags parameter when a partial packet is read. This only applies to
632  * sockets using the datagram protocol. This method does not seem to be implemented
633  * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
634  * flag when a fragmented packet arrives.
635  */
636 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
637 {
638     FIXME("(WSARecvEx) partial packet return value not set \n");
639     return recv(s, buf, len, *flags);
640 }
641
642
643 /***********************************************************************
644  *       s_perror         (WSOCK32.1108)
645  */
646 void WINAPI s_perror(LPCSTR message)
647 {
648     FIXME("(%s): stub\n",message);
649     return;
650 }