api-ms-win-core-comm-l1-1-0: Add dll.
[wine.git] / dlls / wsock32 / socket.c
blob74df2e342e3cd73995a7c0b9f833d82a6fc958ba
1 /*
2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5 * Copyright (C) 2003 Juan Lang.
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include <stdarg.h>
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"
34 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
36 /* internal remapper function for the IP_ constants */
37 static INT _remap_optname(INT level, INT optname)
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;
52 } else {
53 /* don't need to do anything */
54 return optname;
58 /***********************************************************************
59 * setsockopt (WSOCK32.21)
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.
65 INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
67 return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
70 /***********************************************************************
71 * getsockopt (WSOCK32.7)
73 INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
75 return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
78 /***********************************************************************
79 * WsControl (WSOCK32.1001)
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
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.
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.
101 DWORD WINAPI WsControl(DWORD protocol,
102 DWORD action,
103 LPVOID pRequestInfo,
104 LPDWORD pcbRequestInfoLen,
105 LPVOID pResponseInfo,
106 LPDWORD pcbResponseInfoLen)
109 /* Get the command structure into a pointer we can use,
110 rather than void */
111 TDIObjectID *pcommand = pRequestInfo;
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.
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;
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 );
130 switch (action)
132 case WSCNTL_TCPIP_QUERY_INFO:
134 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
135 pcommand->toi_class != INFO_CLASS_PROTOCOL)
137 ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO\n",
138 pcommand->toi_class);
139 return ERROR_BAD_ENVIRONMENT;
142 switch (pcommand->toi_id)
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.
150 case ENTITY_LIST_ID:
152 TDIEntityID *baseptr = pResponseInfo;
153 DWORD numInt, i, ifTable, spaceNeeded;
154 PMIB_IFTABLE table;
156 if (!pcbResponseInfoLen)
157 return ERROR_BAD_ENVIRONMENT;
158 if (pcommand->toi_class != INFO_CLASS_GENERIC)
160 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx\n",
161 pcommand->toi_class);
162 return (ERROR_BAD_ENVIRONMENT);
165 GetNumberOfInterfaces(&numInt);
166 spaceNeeded = sizeof(TDIEntityID) * (numInt * 2 + 3);
168 if (*pcbResponseInfoLen < spaceNeeded)
169 return (ERROR_LOCK_VIOLATION);
171 ifTable = 0;
172 GetIfTable(NULL, &ifTable, FALSE);
173 table = HeapAlloc( GetProcessHeap(), 0, ifTable );
174 if (!table)
175 return ERROR_NOT_ENOUGH_MEMORY;
176 GetIfTable(table, &ifTable, FALSE);
178 spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
179 if (*pcbResponseInfoLen < spaceNeeded)
181 HeapFree( GetProcessHeap(), 0, table );
182 return ERROR_LOCK_VIOLATION;
185 memset(baseptr, 0, spaceNeeded);
187 for (i = 0; i < table->dwNumEntries; i++)
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.
194 if (i == 0)
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++;
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++;
214 *pcbResponseInfoLen = spaceNeeded;
215 HeapFree( GetProcessHeap(), 0, table );
216 break;
219 /* Returns MIB-II statistics for an interface */
220 case ENTITY_TYPE_ID:
221 switch (pcommand->toi_entity.tei_entity)
223 case IF_GENERIC:
224 if (pcommand->toi_class == INFO_CLASS_GENERIC)
226 if (!pcbResponseInfoLen)
227 return ERROR_BAD_ENVIRONMENT;
228 *((ULONG *)pResponseInfo) = IF_MIB;
229 *pcbResponseInfoLen = sizeof(ULONG);
231 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
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);
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)
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.
253 if (index == 1)
254 return NO_ERROR;
255 ERR ("Error retrieving data for interface index %u\n",
256 index);
257 return ret;
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;
266 break;
268 /* Returns address-translation related data. In our case, this is
269 * ARP.
271 case AT_ENTITY:
272 if (pcommand->toi_class == INFO_CLASS_GENERIC)
274 if (!pcbResponseInfoLen)
275 return ERROR_BAD_ENVIRONMENT;
276 *((ULONG *)pResponseInfo) = AT_ARP;
277 *pcbResponseInfoLen = sizeof(ULONG);
279 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
281 PMIB_IPNETTABLE table;
282 DWORD size;
283 PULONG output = pResponseInfo;
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(), 0, 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.
302 *(output++) = table->dwNumEntries;
303 *output = table->table[0].dwIndex;
304 HeapFree( GetProcessHeap(), 0, table );
305 *pcbResponseInfoLen = sizeof(ULONG) * 2;
307 break;
309 /* Returns connectionless network layer statistics--in our case,
310 * this is IP.
312 case CL_NL_ENTITY:
313 if (pcommand->toi_class == INFO_CLASS_GENERIC)
315 if (!pcbResponseInfoLen)
316 return ERROR_BAD_ENVIRONMENT;
317 *((ULONG *)pResponseInfo) = CL_NL_IP;
318 *pcbResponseInfoLen = sizeof(ULONG);
320 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
322 if (!pcbResponseInfoLen)
323 return ERROR_BAD_ENVIRONMENT;
324 if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
325 return ERROR_LOCK_VIOLATION;
326 GetIpStatistics(pResponseInfo);
328 *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
330 break;
332 /* Returns connectionless transport layer statistics--in our case,
333 * this is UDP.
335 case CL_TL_ENTITY:
336 if (pcommand->toi_class == INFO_CLASS_GENERIC)
338 if (!pcbResponseInfoLen)
339 return ERROR_BAD_ENVIRONMENT;
340 *((ULONG *)pResponseInfo) = CL_TL_UDP;
341 *pcbResponseInfoLen = sizeof(ULONG);
343 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
345 if (!pcbResponseInfoLen)
346 return ERROR_BAD_ENVIRONMENT;
347 if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS))
348 return ERROR_LOCK_VIOLATION;
349 GetUdpStatistics(pResponseInfo);
350 *pcbResponseInfoLen = sizeof(MIB_UDPSTATS);
352 break;
354 /* Returns connection-oriented transport layer statistics--in our
355 * case, this is TCP.
357 case CO_TL_ENTITY:
358 if (pcommand->toi_class == INFO_CLASS_GENERIC)
360 if (!pcbResponseInfoLen)
361 return ERROR_BAD_ENVIRONMENT;
362 *((ULONG *)pResponseInfo) = CO_TL_TCP;
363 *pcbResponseInfoLen = sizeof(ULONG);
365 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
367 if (!pcbResponseInfoLen)
368 return ERROR_BAD_ENVIRONMENT;
369 if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS))
370 return ERROR_LOCK_VIOLATION;
371 GetTcpStatistics(pResponseInfo);
372 *pcbResponseInfoLen = sizeof(MIB_TCPSTATS);
374 break;
376 default:
377 ERR("Unknown entity %ld for ENTITY_TYPE_ID query\n",
378 pcommand->toi_entity.tei_entity);
380 break;
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.
386 case IP_MIB_ADDRTABLE_ENTRY_ID:
388 DWORD index = pcommand->toi_entity.tei_instance;
389 PMIB_IPADDRROW baseIPInfo = pResponseInfo;
390 PMIB_IPADDRTABLE table;
391 DWORD tableSize, i;
393 if (!pcbResponseInfoLen)
394 return ERROR_BAD_ENVIRONMENT;
395 if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
396 return (ERROR_LOCK_VIOLATION);
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(), 0, tableSize );
403 if (!table)
404 return ERROR_NOT_ENOUGH_MEMORY;
405 GetIpAddrTable(table, &tableSize, FALSE);
406 for (i = 0; i < table->dwNumEntries; i++)
408 if (table->table[i].dwIndex == index)
410 TRACE("Found IP info for tei_instance 0x%x:\n", index);
411 TRACE("IP 0x%08x, mask 0x%08x\n", table->table[i].dwAddr,
412 table->table[i].dwMask);
413 *baseIPInfo = table->table[i];
414 break;
417 HeapFree( GetProcessHeap(), 0, table );
419 *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
420 break;
423 case IP_MIB_TABLE_ENTRY_ID:
425 switch (pcommand->toi_entity.tei_entity)
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:
438 DWORD routeTableSize, numRoutes, ndx, ret;
439 PMIB_IPFORWARDTABLE table;
440 IPRouteEntry *winRouteTable = pResponseInfo;
442 if (!pcbResponseInfoLen)
443 return ERROR_BAD_ENVIRONMENT;
444 ret = GetIpForwardTable(NULL, &routeTableSize, FALSE);
445 if (ret != ERROR_INSUFFICIENT_BUFFER)
446 return ret;
447 numRoutes = (routeTableSize - sizeof(MIB_IPFORWARDTABLE))
448 / sizeof(MIB_IPFORWARDROW) + 1;
449 if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
450 return (ERROR_LOCK_VIOLATION);
451 table = HeapAlloc( GetProcessHeap(), 0, routeTableSize );
452 if (!table)
453 return ERROR_NOT_ENOUGH_MEMORY;
454 ret = GetIpForwardTable(table, &routeTableSize, FALSE);
455 if (ret != NO_ERROR) {
456 HeapFree( GetProcessHeap(), 0, table );
457 return ret;
460 memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
461 for (ndx = 0; ndx < table->dwNumEntries; ndx++)
463 winRouteTable->ire_addr = table->table[ndx].dwForwardDest;
464 winRouteTable->ire_index =
465 table->table[ndx].dwForwardIfIndex;
466 winRouteTable->ire_metric =
467 table->table[ndx].dwForwardMetric1;
468 /* winRouteTable->ire_option4 =
469 winRouteTable->ire_option5 =
470 winRouteTable->ire_option6 = */
471 winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop;
472 /* winRouteTable->ire_option8 =
473 winRouteTable->ire_option9 =
474 winRouteTable->ire_option10 = */
475 winRouteTable->ire_mask = table->table[ndx].dwForwardMask;
476 /* winRouteTable->ire_option12 = */
477 winRouteTable++;
480 /* calculate the length of the data in the output buffer */
481 *pcbResponseInfoLen = sizeof(IPRouteEntry) *
482 table->dwNumEntries;
484 HeapFree( GetProcessHeap(), 0, table );
486 break;
488 case AT_ARP:
490 DWORD arpTableSize, numEntries, ret;
491 PMIB_IPNETTABLE table;
493 if (!pcbResponseInfoLen)
494 return ERROR_BAD_ENVIRONMENT;
495 ret = GetIpNetTable(NULL, &arpTableSize, FALSE);
496 if (ret != ERROR_INSUFFICIENT_BUFFER)
497 return ret;
498 numEntries = (arpTableSize - sizeof(MIB_IPNETTABLE))
499 / sizeof(MIB_IPNETROW) + 1;
500 if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * numEntries)
501 return (ERROR_LOCK_VIOLATION);
502 table = HeapAlloc( GetProcessHeap(), 0, arpTableSize );
503 if (!table)
504 return ERROR_NOT_ENOUGH_MEMORY;
505 ret = GetIpNetTable(table, &arpTableSize, FALSE);
506 if (ret != NO_ERROR) {
507 HeapFree( GetProcessHeap(), 0, table );
508 return ret;
510 if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) *
511 table->dwNumEntries)
513 HeapFree( GetProcessHeap(), 0, table );
514 return ERROR_LOCK_VIOLATION;
516 memcpy(pResponseInfo, table->table, sizeof(MIB_IPNETROW) *
517 table->dwNumEntries);
519 /* calculate the length of the data in the output buffer */
520 *pcbResponseInfoLen = sizeof(MIB_IPNETROW) *
521 table->dwNumEntries;
523 HeapFree( GetProcessHeap(), 0, table );
525 break;
527 case CO_TL_ENTITY:
529 DWORD tcpTableSize, numEntries, ret;
530 PMIB_TCPTABLE table;
531 DWORD i;
533 if (!pcbResponseInfoLen)
534 return ERROR_BAD_ENVIRONMENT;
535 ret = GetTcpTable(NULL, &tcpTableSize, FALSE);
536 if (ret != ERROR_INSUFFICIENT_BUFFER)
537 return ret;
538 numEntries = (tcpTableSize - sizeof(MIB_TCPTABLE))
539 / sizeof(MIB_TCPROW) + 1;
540 if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * numEntries)
541 return (ERROR_LOCK_VIOLATION);
542 table = HeapAlloc( GetProcessHeap(), 0, tcpTableSize );
543 if (!table)
544 return ERROR_NOT_ENOUGH_MEMORY;
545 ret = GetTcpTable(table, &tcpTableSize, FALSE);
546 if (ret != NO_ERROR) {
547 HeapFree( GetProcessHeap(), 0, table );
548 return ret;
550 if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) *
551 table->dwNumEntries)
553 HeapFree( GetProcessHeap(), 0, table );
554 return ERROR_LOCK_VIOLATION;
556 for (i = 0; i < table->dwNumEntries; i++)
558 USHORT sPort;
560 sPort = ntohs((USHORT)table->table[i].dwLocalPort);
561 table->table[i].dwLocalPort = (DWORD)sPort;
562 sPort = ntohs((USHORT)table->table[i].dwRemotePort);
563 table->table[i].dwRemotePort = (DWORD)sPort;
565 memcpy(pResponseInfo, table->table, sizeof(MIB_TCPROW) *
566 table->dwNumEntries);
568 /* calculate the length of the data in the output buffer */
569 *pcbResponseInfoLen = sizeof(MIB_TCPROW) *
570 table->dwNumEntries;
572 HeapFree( GetProcessHeap(), 0, table );
574 break;
576 default:
578 FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
579 pcommand->toi_id, pcommand->toi_entity.tei_entity,
580 pcommand->toi_entity.tei_instance, pcommand->toi_class);
582 return (ERROR_BAD_ENVIRONMENT);
586 break;
589 default:
591 FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
592 pcommand->toi_id, pcommand->toi_entity.tei_entity,
593 pcommand->toi_entity.tei_instance, pcommand->toi_class);
595 return (ERROR_BAD_ENVIRONMENT);
599 break;
602 case WSCNTL_TCPIP_ICMP_ECHO:
604 unsigned int addr = *(unsigned int*)pRequestInfo;
605 #if 0
606 int timeout= *(unsigned int*)(inbuf+4);
607 short x1 = *(unsigned short*)(inbuf+8);
608 short sendbufsize = *(unsigned short*)(inbuf+10);
609 char x2 = *(unsigned char*)(inbuf+12);
610 char ttl = *(unsigned char*)(inbuf+13);
611 char service = *(unsigned char*)(inbuf+14);
612 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
613 #endif
615 FIXME("(ICMP_ECHO) to 0x%08x stub\n", addr);
616 break;
619 default:
620 FIXME("Protocol Not Supported -> protocol=0x%x, action=0x%x, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
621 protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
623 return (WSAEOPNOTSUPP);
627 return (WSCTL_SUCCESS);
632 /***********************************************************************
633 * WSARecvEx (WSOCK32.1107)
635 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
636 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
637 * into the flags parameter when a partial packet is read. This only applies to
638 * sockets using the datagram protocol. This method does not seem to be implemented
639 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
640 * flag when a fragmented packet arrives.
642 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);
649 /***********************************************************************
650 * s_perror (WSOCK32.1108)
652 void WINAPI s_perror(LPCSTR message)
654 FIXME("(%s): stub\n",message);
655 return;