socket.c 25.9 KB
Newer Older
1 2 3 4
/*
 * WSOCK32 specific functions
 *
 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5
 * Copyright (C) 2003 Juan Lang.
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22

23
#include "config.h"
24 25
#include <stdarg.h>

26 27
#include "windef.h"
#include "winbase.h"
28
#include "wine/debug.h"
29 30 31
#include "winsock2.h"
#include "winnt.h"
#include "wscontrol.h"
32
#include "iphlpapi.h"
33

34
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
35

36 37 38 39
/* internal remapper function for the IP_ constants */
static INT _remap_optname(INT level, INT optname)
{
  TRACE("level=%d, optname=%d\n", level, optname);
40
  if (level == IPPROTO_IP) {
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    switch (optname) {       /***** from value *****/
      case 2: return 9;      /* IP_MULTICAST_IF    */
      case 3: return 10;     /* IP_MULTICAST_TTL   */
      case 4: return 11;     /* IP_MULTICAST_LOOP  */
      case 5: return 12;     /* IP_ADD_MEMBERSHIP  */
      case 6: return 13;     /* IP_DROP_MEMBERSHIP */
      case 7: return 4;      /* IP_TTL             */
      case 8: return 3;      /* IP_TOS             */
      case 9: return 14;     /* IP_DONTFRAGMENT    */
      default: FIXME("Unknown optname %d, can't remap!\n", optname); return optname; 
    }
  } else {
    /* don't need to do anything */
    return optname;
  }
}

/***********************************************************************
 *		setsockopt		(WSOCK32.21)
 *
 * We have these forwarders because, for reasons unknown to us mere mortals,
 * the values of the IP_ constants changed between winsock.h and winsock2.h.
 * So, we need to remap them here.
 */
INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
{
  return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
}

/***********************************************************************
 *		getsockopt		(WSOCK32.7)
 */
INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
{
  return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
}
77 78

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
79
 *		WsControl (WSOCK32.1001)
80
 *
81
 * WsControl seems to be an undocumented Win95 function. A lot of
82 83 84 85 86
 * discussion about WsControl can be found on the net, e.g.
 * Subject:      Re: WSOCK32.DLL WsControl Exported Function
 * From:         "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
 * Date:         1997/08/17
 *
87
 * The WSCNTL_TCPIP_QUERY_INFO option is partially implemented based
88
 * on observing the behaviour of WsControl with an app in
89 90 91 92 93
 * Windows 98.  It is not fully implemented, and there could
 * be (are?) errors due to incorrect assumptions made.
 *
 *
 * WsControl returns WSCTL_SUCCESS on success.
94 95 96 97
 * ERROR_LOCK_VIOLATION is returned if the output buffer length
 * (*pcbResponseInfoLen) is too small.  This is an unusual error code, but
 * it matches Win98's behavior.  Other errors come from winerror.h, not from
 * winsock.h.  Again, this is to match Win98 behavior.
98
 *
99
 */
100

101
DWORD WINAPI WsControl(DWORD protocol,
102 103 104 105
                       DWORD action,
                       LPVOID pRequestInfo,
                       LPDWORD pcbRequestInfoLen,
                       LPVOID pResponseInfo,
106
                       LPDWORD pcbResponseInfoLen)
107
{
108

109 110
   /* Get the command structure into a pointer we can use,
      rather than void */
111
   TDIObjectID *pcommand = pRequestInfo;
112

113 114 115 116 117 118 119 120 121 122 123
   /* validate input parameters.  Error codes are from winerror.h, not from
    * winsock.h.  pcbResponseInfoLen is apparently allowed to be NULL for some
    * commands, since winipcfg.exe fails if we ensure it's non-NULL in every
    * case.
    */
   if (protocol != IPPROTO_TCP) return ERROR_INVALID_PARAMETER;
   if (!pcommand) return ERROR_INVALID_PARAMETER;
   if (!pcbRequestInfoLen) return ERROR_INVALID_ACCESS;
   if (*pcbRequestInfoLen < sizeof(TDIObjectID)) return ERROR_INVALID_ACCESS;
   if (!pResponseInfo) return ERROR_INVALID_PARAMETER;
   if (pcommand->toi_type != INFO_TYPE_PROVIDER) return ERROR_INVALID_PARAMETER;
124

125 126 127 128
   TRACE ("   WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
      pcommand->toi_id, pcommand->toi_entity.tei_entity,
      pcommand->toi_entity.tei_instance,
      pcommand->toi_class, pcommand->toi_type );
129 130

   switch (action)
131
   {
132 133 134 135
   case WSCNTL_TCPIP_QUERY_INFO:
   {
      if (pcommand->toi_class != INFO_CLASS_GENERIC &&
       pcommand->toi_class != INFO_CLASS_PROTOCOL)
136
      {
137
         ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO\n",
138 139 140
          pcommand->toi_class);
         return ERROR_BAD_ENVIRONMENT;
      }
141

142 143 144 145 146 147 148 149 150 151
      switch (pcommand->toi_id)
      {
         /* ENTITY_LIST_ID gets the list of "entity IDs", where an entity
            may represent an interface, or a datagram service, or address
            translation, or other fun things.  Typically an entity ID represents
            a class of service, which is further queried for what type it is.
            Different types will then have more specific queries defined.
         */
         case ENTITY_LIST_ID:
         {
152
            TDIEntityID *baseptr = pResponseInfo;
153 154
            DWORD numInt, i, ifTable, spaceNeeded;
            PMIB_IFTABLE table;
155

156 157 158 159
            if (!pcbResponseInfoLen)
               return ERROR_BAD_ENVIRONMENT;
            if (pcommand->toi_class != INFO_CLASS_GENERIC)
            {
160
               FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx\n",
161 162 163
                    pcommand->toi_class);
               return (ERROR_BAD_ENVIRONMENT);
            }
164

165
            GetNumberOfInterfaces(&numInt);
166
            spaceNeeded = sizeof(TDIEntityID) * (numInt * 2 + 3);
167

168 169
            if (*pcbResponseInfoLen < spaceNeeded)
               return (ERROR_LOCK_VIOLATION);
170

171 172
            ifTable = 0;
            GetIfTable(NULL, &ifTable, FALSE);
173
            table = HeapAlloc( GetProcessHeap(), 0, ifTable );
174 175 176
            if (!table)
               return ERROR_NOT_ENOUGH_MEMORY;
            GetIfTable(table, &ifTable, FALSE);
177

178 179 180
            spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
            if (*pcbResponseInfoLen < spaceNeeded)
            {
181 182
               HeapFree( GetProcessHeap(), 0, table );
               return ERROR_LOCK_VIOLATION;
183
            }
184

185
            memset(baseptr, 0, spaceNeeded);
186

187
            for (i = 0; i < table->dwNumEntries; i++)
188
            {
189 190 191 192
               /* Return IF_GENERIC and CL_NL_ENTITY on every interface, and
                * AT_ENTITY, CL_TL_ENTITY, and CO_TL_ENTITY on the first
                * interface.  MS returns them only on the loopback interface,
                * but it doesn't seem to matter.
193 194
                */
               if (i == 0)
195
               {
196 197 198 199 200 201 202 203 204 205
                  baseptr->tei_entity = CO_TL_ENTITY;
                  baseptr->tei_instance = table->table[i].dwIndex;
                  baseptr++;
                  baseptr->tei_entity = CL_TL_ENTITY;
                  baseptr->tei_instance = table->table[i].dwIndex;
                  baseptr++;
                  baseptr->tei_entity = AT_ENTITY;
                  baseptr->tei_instance = table->table[i].dwIndex;
                  baseptr++;
               }
206 207 208
               baseptr->tei_entity = CL_NL_ENTITY;
               baseptr->tei_instance = table->table[i].dwIndex;
               baseptr++;
209 210 211 212
               baseptr->tei_entity = IF_GENERIC;
               baseptr->tei_instance = table->table[i].dwIndex;
               baseptr++;
            }
213

214
            *pcbResponseInfoLen = spaceNeeded;
215
            HeapFree( GetProcessHeap(), 0, table );
216 217
            break;
         }
218

219 220 221 222 223 224 225 226 227 228 229
         /* Returns MIB-II statistics for an interface */
         case ENTITY_TYPE_ID:
            switch (pcommand->toi_entity.tei_entity)
            {
            case IF_GENERIC:
               if (pcommand->toi_class == INFO_CLASS_GENERIC)
               {
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  *((ULONG *)pResponseInfo) = IF_MIB;
                  *pcbResponseInfoLen = sizeof(ULONG);
230
               }
231
               else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
232
               {
233 234 235 236 237 238 239 240 241 242 243 244
                  MIB_IFROW row;
                  DWORD index = pcommand->toi_entity.tei_instance, ret;
                  DWORD size = sizeof(row) - sizeof(row.wszName) -
                   sizeof(row.bDescr);

                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  if (*pcbResponseInfoLen < size)
                     return (ERROR_LOCK_VIOLATION);
                  row.dwIndex = index;
                  ret = GetIfEntry(&row);
                  if (ret != NO_ERROR)
245
                  {
246 247 248 249 250 251 252 253 254
                     /* FIXME: Win98's arp.exe insists on querying index 1 for
                      * its MIB-II stats, regardless of the tei_instances
                      * returned in the ENTITY_LIST query above.  If the query
                      * fails, arp.exe fails.  So, I do this hack return value
                      * if index is 1 and the query failed just to get arp.exe
                      * to continue.
                      */
                     if (index == 1)
                        return NO_ERROR;
255
                     ERR ("Error retrieving data for interface index %u\n",
256 257
                      index);
                     return ret;
258
                  }
259 260 261 262 263 264 265 266
                  size = sizeof(row) - sizeof(row.wszName) -
                   sizeof(row.bDescr) + row.dwDescrLen;
                  if (*pcbResponseInfoLen < size)
                     return (ERROR_LOCK_VIOLATION);
                  memcpy(pResponseInfo, &row.dwIndex, size);
                  *pcbResponseInfoLen = size;
               }
               break;
267

268 269 270 271 272 273 274 275 276 277
            /* Returns address-translation related data.  In our case, this is
             * ARP.
             */
            case AT_ENTITY:
               if (pcommand->toi_class == INFO_CLASS_GENERIC)
               {
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  *((ULONG *)pResponseInfo) = AT_ARP;
                  *pcbResponseInfoLen = sizeof(ULONG);
278
               }
279
               else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
280
               {
281 282
                  PMIB_IPNETTABLE table;
                  DWORD size;
283
                  PULONG output = pResponseInfo;
284 285 286 287 288 289

                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  if (*pcbResponseInfoLen < sizeof(ULONG) * 2)
                     return (ERROR_LOCK_VIOLATION);
                  GetIpNetTable(NULL, &size, FALSE);
290
                  table = HeapAlloc( GetProcessHeap(), 0, size );
291 292 293 294 295 296 297 298 299 300 301 302 303
                  if (!table)
                     return ERROR_NOT_ENOUGH_MEMORY;
                  GetIpNetTable(table, &size, FALSE);
                  /* FIXME: I don't understand the meaning of the ARP output
                   * very well, but it seems to indicate how many ARP entries
                   * exist.  I don't know whether this should reflect the
                   * number per interface, as I'm only testing with a single
                   * interface.  So, I lie and say all ARP entries exist on
                   * a single interface--the first one that appears in the
                   * ARP table.
                   */
                  *(output++) = table->dwNumEntries;
                  *output = table->table[0].dwIndex;
304
                  HeapFree( GetProcessHeap(), 0, table );
305
                  *pcbResponseInfoLen = sizeof(ULONG) * 2;
306 307 308
               }
               break;

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
            /* Returns connectionless network layer statistics--in our case,
             * this is IP.
             */
            case CL_NL_ENTITY:
               if (pcommand->toi_class == INFO_CLASS_GENERIC)
               {
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  *((ULONG *)pResponseInfo) = CL_NL_IP;
                  *pcbResponseInfoLen = sizeof(ULONG);
               }
               else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
               {
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
                     return ERROR_LOCK_VIOLATION;
326
                  GetIpStatistics(pResponseInfo);
327

328 329 330
                  *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
               }
               break;
331

332 333 334 335 336
            /* Returns connectionless transport layer statistics--in our case,
             * this is UDP.
             */
            case CL_TL_ENTITY:
               if (pcommand->toi_class == INFO_CLASS_GENERIC)
337
               {
338 339 340 341
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  *((ULONG *)pResponseInfo) = CL_TL_UDP;
                  *pcbResponseInfoLen = sizeof(ULONG);
342
               }
343
               else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
344
               {
345 346 347 348
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS))
                     return ERROR_LOCK_VIOLATION;
349
                  GetUdpStatistics(pResponseInfo);
350
                  *pcbResponseInfoLen = sizeof(MIB_UDPSTATS);
351
               }
352
               break;
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
            /* Returns connection-oriented transport layer statistics--in our
             * case, this is TCP.
             */
            case CO_TL_ENTITY:
               if (pcommand->toi_class == INFO_CLASS_GENERIC)
               {
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  *((ULONG *)pResponseInfo) = CO_TL_TCP;
                  *pcbResponseInfoLen = sizeof(ULONG);
               }
               else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
               {
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
                  if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS))
                     return ERROR_LOCK_VIOLATION;
371
                  GetTcpStatistics(pResponseInfo);
372 373
                  *pcbResponseInfoLen = sizeof(MIB_TCPSTATS);
               }
374 375
               break;

376
            default:
377
               ERR("Unknown entity %ld for ENTITY_TYPE_ID query\n",
378 379 380
                pcommand->toi_entity.tei_entity);
         }
         break;
381

382 383 384 385 386 387 388
         /* This call returns the IP address, subnet mask, and broadcast
          * address for an interface.  If there are multiple IP addresses for
          * the interface with the given index, returns the "first" one.
          */
         case IP_MIB_ADDRTABLE_ENTRY_ID:
         {
            DWORD index = pcommand->toi_entity.tei_instance;
389
            PMIB_IPADDRROW baseIPInfo = pResponseInfo;
390 391 392 393 394 395 396 397 398 399 400 401
            PMIB_IPADDRTABLE table;
            DWORD tableSize, i;

            if (!pcbResponseInfoLen)
               return ERROR_BAD_ENVIRONMENT;
            if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
               return (ERROR_LOCK_VIOLATION);

            /* get entire table, because there isn't an exported function that
               gets just one entry. */
            tableSize = 0;
            GetIpAddrTable(NULL, &tableSize, FALSE);
402
            table = HeapAlloc( GetProcessHeap(), 0, tableSize );
403 404 405 406
            if (!table)
               return ERROR_NOT_ENOUGH_MEMORY;
            GetIpAddrTable(table, &tableSize, FALSE);
            for (i = 0; i < table->dwNumEntries; i++)
407
            {
408 409
               if (table->table[i].dwIndex == index)
               {
410 411
                  TRACE("Found IP info for tei_instance 0x%x:\n", index);
                  TRACE("IP 0x%08x, mask 0x%08x\n", table->table[i].dwAddr,
412
                   table->table[i].dwMask);
413
                  *baseIPInfo = table->table[i];
414 415
                  break;
               }
416
            }
417
            HeapFree( GetProcessHeap(), 0, table );
418

419 420 421
            *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
            break;
         }
422

423
         case IP_MIB_TABLE_ENTRY_ID:
424
         {
425 426 427 428 429 430 431 432 433 434 435 436 437
            switch (pcommand->toi_entity.tei_entity)
            {
            /* This call returns the routing table.
             * No official documentation found, even the name of the command is unknown.
             * Work is based on
             * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
             * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
             * pcommand->toi_entity.tei_instance seems to be the interface number
             * but route.exe outputs only the information for the last interface
             * if only the routes for the pcommand->toi_entity.tei_instance
             * interface are returned. */
               case CL_NL_ENTITY:
               {
438
                  DWORD routeTableSize, numRoutes, ndx, ret;
439
                  PMIB_IPFORWARDTABLE table;
440
                  IPRouteEntry *winRouteTable  = pResponseInfo;
441

442 443
                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
444 445 446
                  ret = GetIpForwardTable(NULL, &routeTableSize, FALSE);
                  if (ret != ERROR_INSUFFICIENT_BUFFER)
                      return ret;
447 448
                  numRoutes = (routeTableSize - sizeof(MIB_IPFORWARDTABLE))
                   / sizeof(MIB_IPFORWARDROW) + 1;
449 450
                  if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
                     return (ERROR_LOCK_VIOLATION);
451
                  table = HeapAlloc( GetProcessHeap(), 0, routeTableSize );
452 453
                  if (!table)
                     return ERROR_NOT_ENOUGH_MEMORY;
454 455
                  ret = GetIpForwardTable(table, &routeTableSize, FALSE);
                  if (ret != NO_ERROR) {
456
                     HeapFree( GetProcessHeap(), 0, table );
457 458
                     return ret;
                  }
459

460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
                  memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
                  for (ndx = 0; ndx < table->dwNumEntries; ndx++)
                  {
                     winRouteTable->ire_addr = table->table[ndx].dwForwardDest;
                     winRouteTable->ire_index =
                      table->table[ndx].dwForwardIfIndex;
                     winRouteTable->ire_metric =
                      table->table[ndx].dwForwardMetric1;
                     /* winRouteTable->ire_option4 =
                     winRouteTable->ire_option5 =
                     winRouteTable->ire_option6 = */
                     winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop;
                     /* winRouteTable->ire_option8 =
                     winRouteTable->ire_option9 =
                     winRouteTable->ire_option10 = */
                     winRouteTable->ire_mask = table->table[ndx].dwForwardMask;
                     /* winRouteTable->ire_option12 = */
                     winRouteTable++;
                  }
479

480 481 482
                  /* calculate the length of the data in the output buffer */
                  *pcbResponseInfoLen = sizeof(IPRouteEntry) *
                   table->dwNumEntries;
483

484
                  HeapFree( GetProcessHeap(), 0, table );
485 486 487 488 489 490 491 492 493 494
               }
               break;

               case AT_ARP:
               {
                  DWORD arpTableSize, numEntries, ret;
                  PMIB_IPNETTABLE table;

                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
495 496 497
                  ret = GetIpNetTable(NULL, &arpTableSize, FALSE);
                  if (ret != ERROR_INSUFFICIENT_BUFFER)
                      return ret;
498 499
                  numEntries = (arpTableSize - sizeof(MIB_IPNETTABLE))
                   / sizeof(MIB_IPNETROW) + 1;
500 501
                  if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * numEntries)
                     return (ERROR_LOCK_VIOLATION);
502
                  table = HeapAlloc( GetProcessHeap(), 0, arpTableSize );
503 504 505
                  if (!table)
                     return ERROR_NOT_ENOUGH_MEMORY;
                  ret = GetIpNetTable(table, &arpTableSize, FALSE);
506
                  if (ret != NO_ERROR) {
507
                     HeapFree( GetProcessHeap(), 0, table );
508
                     return ret;
509
                  }
510 511 512
                  if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) *
                   table->dwNumEntries)
                  {
513
                     HeapFree( GetProcessHeap(), 0, table );
514 515 516 517 518 519 520 521 522
                     return ERROR_LOCK_VIOLATION;
                  }
                  memcpy(pResponseInfo, table->table, sizeof(MIB_IPNETROW) *
                   table->dwNumEntries);

                  /* calculate the length of the data in the output buffer */
                  *pcbResponseInfoLen = sizeof(MIB_IPNETROW) *
                   table->dwNumEntries;

523
                  HeapFree( GetProcessHeap(), 0, table );
524 525 526
               }
               break;

527 528 529 530 531 532 533 534
               case CO_TL_ENTITY:
               {
                  DWORD tcpTableSize, numEntries, ret;
                  PMIB_TCPTABLE table;
                  DWORD i;

                  if (!pcbResponseInfoLen)
                     return ERROR_BAD_ENVIRONMENT;
535 536 537
                  ret = GetTcpTable(NULL, &tcpTableSize, FALSE);
                  if (ret != ERROR_INSUFFICIENT_BUFFER)
                      return ret;
538 539
                  numEntries = (tcpTableSize - sizeof(MIB_TCPTABLE))
                   / sizeof(MIB_TCPROW) + 1;
540 541
                  if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * numEntries)
                     return (ERROR_LOCK_VIOLATION);
542
                  table = HeapAlloc( GetProcessHeap(), 0, tcpTableSize );
543 544 545
                  if (!table)
                     return ERROR_NOT_ENOUGH_MEMORY;
                  ret = GetTcpTable(table, &tcpTableSize, FALSE);
546
                  if (ret != NO_ERROR) {
547
                     HeapFree( GetProcessHeap(), 0, table );
548
                     return ret;
549
                  }
550 551 552
                  if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) *
                   table->dwNumEntries)
                  {
553
                     HeapFree( GetProcessHeap(), 0, table );
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
                     return ERROR_LOCK_VIOLATION;
                  }
                  for (i = 0; i < table->dwNumEntries; i++)
                  {
                     USHORT sPort;

                     sPort = ntohs((USHORT)table->table[i].dwLocalPort);
                     table->table[i].dwLocalPort = (DWORD)sPort;
                     sPort = ntohs((USHORT)table->table[i].dwRemotePort);
                     table->table[i].dwRemotePort = (DWORD)sPort;
                  }
                  memcpy(pResponseInfo, table->table, sizeof(MIB_TCPROW) *
                   table->dwNumEntries);

                  /* calculate the length of the data in the output buffer */
                  *pcbResponseInfoLen = sizeof(MIB_TCPROW) *
                   table->dwNumEntries;

572
                  HeapFree( GetProcessHeap(), 0, table );
573 574 575
               }
               break;

576 577 578 579 580 581 582 583 584
               default:
               {
                  FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
                     pcommand->toi_id, pcommand->toi_entity.tei_entity,
                     pcommand->toi_entity.tei_instance, pcommand->toi_class);

                  return (ERROR_BAD_ENVIRONMENT);
               }
            }
585
         }
586
         break;
587 588


589 590 591 592 593 594 595 596
         default:
         {
            FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
               pcommand->toi_id, pcommand->toi_entity.tei_entity,
               pcommand->toi_entity.tei_instance, pcommand->toi_class);

            return (ERROR_BAD_ENVIRONMENT);
         }
597 598
      }

599 600
      break;
   }
601

602 603 604
   case WSCNTL_TCPIP_ICMP_ECHO:
   {
      unsigned int addr = *(unsigned int*)pRequestInfo;
605
#if 0
606 607 608 609 610 611 612
         int timeout= *(unsigned int*)(inbuf+4);
         short x1 = *(unsigned short*)(inbuf+8);
         short sendbufsize = *(unsigned short*)(inbuf+10);
         char x2 = *(unsigned char*)(inbuf+12);
         char ttl = *(unsigned char*)(inbuf+13);
         char service = *(unsigned char*)(inbuf+14);
         char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
613
#endif
614

615
      FIXME("(ICMP_ECHO) to 0x%08x stub\n", addr);
616
      break;
617
   }
618

619
   default:
620
      FIXME("Protocol Not Supported -> protocol=0x%x, action=0x%x, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
621 622 623 624 625
       protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);

      return (WSAEOPNOTSUPP);

   }
626 627

   return (WSCTL_SUCCESS);
628 629
}

630 631


632
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
633
 *		WSARecvEx			(WSOCK32.1107)
634 635 636 637 638 639 640 641 642 643
 *
 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
 * into the flags parameter when a partial packet is read. This only applies to
 * sockets using the datagram protocol. This method does not seem to be implemented
 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
 * flag when a fragmented packet arrives.
 */
INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
{
644
    FIXME("(WSARecvEx) partial packet return value not set\n");
645
    return recv(s, buf, len, *flags);
646
}
647 648


649
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
650
 *       s_perror         (WSOCK32.1108)
651
 */
652
void WINAPI s_perror(LPCSTR message)
653 654 655 656
{
    FIXME("(%s): stub\n",message);
    return;
}