wow64: Preserve TEB exception frame in Wow64KiUserCallbackDispatcher.
[wine.git] / dlls / wsock32 / socket.c
blob2df54b2280ada874671c0c89d1a88f1c88f3a345
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
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wine/debug.h"
27 #include "winsock2.h"
28 #include "winnt.h"
29 #include "wscontrol.h"
30 #include "iphlpapi.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
34 /* internal remapper function for the IP_ constants */
35 static INT _remap_optname(INT level, INT optname)
37 TRACE("level=%d, optname=%d\n", level, optname);
38 if (level == IPPROTO_IP) {
39 switch (optname) { /***** from value *****/
40 case 2: return 9; /* IP_MULTICAST_IF */
41 case 3: return 10; /* IP_MULTICAST_TTL */
42 case 4: return 11; /* IP_MULTICAST_LOOP */
43 case 5: return 12; /* IP_ADD_MEMBERSHIP */
44 case 6: return 13; /* IP_DROP_MEMBERSHIP */
45 case 7: return 4; /* IP_TTL */
46 case 8: return 3; /* IP_TOS */
47 case 9: return 14; /* IP_DONTFRAGMENT */
48 default: FIXME("Unknown optname %d, can't remap!\n", optname); return optname;
50 } else {
51 /* don't need to do anything */
52 return optname;
56 /***********************************************************************
57 * setsockopt (WSOCK32.21)
59 * We have these forwarders because, for reasons unknown to us mere mortals,
60 * the values of the IP_ constants changed between winsock.h and winsock2.h.
61 * So, we need to remap them here.
63 INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
65 return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
68 /***********************************************************************
69 * getsockopt (WSOCK32.7)
71 INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
73 return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
76 /***********************************************************************
77 * WsControl (WSOCK32.1001)
79 * WsControl seems to be an undocumented Win95 function. A lot of
80 * discussion about WsControl can be found on the net, e.g.
81 * Subject: Re: WSOCK32.DLL WsControl Exported Function
82 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
83 * Date: 1997/08/17
85 * The WSCNTL_TCPIP_QUERY_INFO option is partially implemented based
86 * on observing the behaviour of WsControl with an app in
87 * Windows 98. It is not fully implemented, and there could
88 * be (are?) errors due to incorrect assumptions made.
91 * WsControl returns WSCTL_SUCCESS on success.
92 * ERROR_LOCK_VIOLATION is returned if the output buffer length
93 * (*pcbResponseInfoLen) is too small. This is an unusual error code, but
94 * it matches Win98's behavior. Other errors come from winerror.h, not from
95 * winsock.h. Again, this is to match Win98 behavior.
99 DWORD WINAPI WsControl(DWORD protocol,
100 DWORD action,
101 LPVOID pRequestInfo,
102 LPDWORD pcbRequestInfoLen,
103 LPVOID pResponseInfo,
104 LPDWORD pcbResponseInfoLen)
107 /* Get the command structure into a pointer we can use,
108 rather than void */
109 TDIObjectID *pcommand = pRequestInfo;
111 /* validate input parameters. Error codes are from winerror.h, not from
112 * winsock.h. pcbResponseInfoLen is apparently allowed to be NULL for some
113 * commands, since winipcfg.exe fails if we ensure it's non-NULL in every
114 * case.
116 if (protocol != IPPROTO_TCP) return ERROR_INVALID_PARAMETER;
117 if (!pcommand) return ERROR_INVALID_PARAMETER;
118 if (!pcbRequestInfoLen) return ERROR_INVALID_ACCESS;
119 if (*pcbRequestInfoLen < sizeof(TDIObjectID)) return ERROR_INVALID_ACCESS;
120 if (!pResponseInfo) return ERROR_INVALID_PARAMETER;
121 if (pcommand->toi_type != INFO_TYPE_PROVIDER) return ERROR_INVALID_PARAMETER;
123 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
124 pcommand->toi_id, pcommand->toi_entity.tei_entity,
125 pcommand->toi_entity.tei_instance,
126 pcommand->toi_class, pcommand->toi_type );
128 switch (action)
130 case WSCNTL_TCPIP_QUERY_INFO:
132 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
133 pcommand->toi_class != INFO_CLASS_PROTOCOL)
135 ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO\n",
136 pcommand->toi_class);
137 return ERROR_BAD_ENVIRONMENT;
140 switch (pcommand->toi_id)
142 /* ENTITY_LIST_ID gets the list of "entity IDs", where an entity
143 may represent an interface, or a datagram service, or address
144 translation, or other fun things. Typically an entity ID represents
145 a class of service, which is further queried for what type it is.
146 Different types will then have more specific queries defined.
148 case ENTITY_LIST_ID:
150 TDIEntityID *baseptr = pResponseInfo;
151 DWORD numInt, i, ifTable, spaceNeeded;
152 PMIB_IFTABLE table;
154 if (!pcbResponseInfoLen)
155 return ERROR_BAD_ENVIRONMENT;
156 if (pcommand->toi_class != INFO_CLASS_GENERIC)
158 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx\n",
159 pcommand->toi_class);
160 return (ERROR_BAD_ENVIRONMENT);
163 GetNumberOfInterfaces(&numInt);
164 spaceNeeded = sizeof(TDIEntityID) * (numInt * 2 + 3);
166 if (*pcbResponseInfoLen < spaceNeeded)
167 return (ERROR_LOCK_VIOLATION);
169 ifTable = 0;
170 GetIfTable(NULL, &ifTable, FALSE);
171 table = HeapAlloc( GetProcessHeap(), 0, ifTable );
172 if (!table)
173 return ERROR_NOT_ENOUGH_MEMORY;
174 GetIfTable(table, &ifTable, FALSE);
176 spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4);
177 if (*pcbResponseInfoLen < spaceNeeded)
179 HeapFree( GetProcessHeap(), 0, table );
180 return ERROR_LOCK_VIOLATION;
183 memset(baseptr, 0, spaceNeeded);
185 for (i = 0; i < table->dwNumEntries; i++)
187 /* Return IF_GENERIC and CL_NL_ENTITY on every interface, and
188 * AT_ENTITY, CL_TL_ENTITY, and CO_TL_ENTITY on the first
189 * interface. MS returns them only on the loopback interface,
190 * but it doesn't seem to matter.
192 if (i == 0)
194 baseptr->tei_entity = CO_TL_ENTITY;
195 baseptr->tei_instance = table->table[i].dwIndex;
196 baseptr++;
197 baseptr->tei_entity = CL_TL_ENTITY;
198 baseptr->tei_instance = table->table[i].dwIndex;
199 baseptr++;
200 baseptr->tei_entity = AT_ENTITY;
201 baseptr->tei_instance = table->table[i].dwIndex;
202 baseptr++;
204 baseptr->tei_entity = CL_NL_ENTITY;
205 baseptr->tei_instance = table->table[i].dwIndex;
206 baseptr++;
207 baseptr->tei_entity = IF_GENERIC;
208 baseptr->tei_instance = table->table[i].dwIndex;
209 baseptr++;
212 *pcbResponseInfoLen = spaceNeeded;
213 HeapFree( GetProcessHeap(), 0, table );
214 break;
217 /* Returns MIB-II statistics for an interface */
218 case ENTITY_TYPE_ID:
219 switch (pcommand->toi_entity.tei_entity)
221 case IF_GENERIC:
222 if (pcommand->toi_class == INFO_CLASS_GENERIC)
224 if (!pcbResponseInfoLen)
225 return ERROR_BAD_ENVIRONMENT;
226 *((ULONG *)pResponseInfo) = IF_MIB;
227 *pcbResponseInfoLen = sizeof(ULONG);
229 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
231 MIB_IFROW row;
232 DWORD index = pcommand->toi_entity.tei_instance, ret;
233 DWORD size = sizeof(row) - sizeof(row.wszName) -
234 sizeof(row.bDescr);
236 if (!pcbResponseInfoLen)
237 return ERROR_BAD_ENVIRONMENT;
238 if (*pcbResponseInfoLen < size)
239 return (ERROR_LOCK_VIOLATION);
240 row.dwIndex = index;
241 ret = GetIfEntry(&row);
242 if (ret != NO_ERROR)
244 /* FIXME: Win98's arp.exe insists on querying index 1 for
245 * its MIB-II stats, regardless of the tei_instances
246 * returned in the ENTITY_LIST query above. If the query
247 * fails, arp.exe fails. So, I do this hack return value
248 * if index is 1 and the query failed just to get arp.exe
249 * to continue.
251 if (index == 1)
252 return NO_ERROR;
253 ERR ("Error retrieving data for interface index %lu\n",
254 index);
255 return ret;
257 size = sizeof(row) - sizeof(row.wszName) -
258 sizeof(row.bDescr) + row.dwDescrLen;
259 if (*pcbResponseInfoLen < size)
260 return (ERROR_LOCK_VIOLATION);
261 memcpy(pResponseInfo, &row.dwIndex, size);
262 *pcbResponseInfoLen = size;
264 break;
266 /* Returns address-translation related data. In our case, this is
267 * ARP.
269 case AT_ENTITY:
270 if (pcommand->toi_class == INFO_CLASS_GENERIC)
272 if (!pcbResponseInfoLen)
273 return ERROR_BAD_ENVIRONMENT;
274 *((ULONG *)pResponseInfo) = AT_ARP;
275 *pcbResponseInfoLen = sizeof(ULONG);
277 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
279 PMIB_IPNETTABLE table;
280 DWORD size;
281 PULONG output = pResponseInfo;
283 if (!pcbResponseInfoLen)
284 return ERROR_BAD_ENVIRONMENT;
285 if (*pcbResponseInfoLen < sizeof(ULONG) * 2)
286 return (ERROR_LOCK_VIOLATION);
287 GetIpNetTable(NULL, &size, FALSE);
288 table = HeapAlloc( GetProcessHeap(), 0, size );
289 if (!table)
290 return ERROR_NOT_ENOUGH_MEMORY;
291 GetIpNetTable(table, &size, FALSE);
292 /* FIXME: I don't understand the meaning of the ARP output
293 * very well, but it seems to indicate how many ARP entries
294 * exist. I don't know whether this should reflect the
295 * number per interface, as I'm only testing with a single
296 * interface. So, I lie and say all ARP entries exist on
297 * a single interface--the first one that appears in the
298 * ARP table.
300 *(output++) = table->dwNumEntries;
301 *output = table->table[0].dwIndex;
302 HeapFree( GetProcessHeap(), 0, table );
303 *pcbResponseInfoLen = sizeof(ULONG) * 2;
305 break;
307 /* Returns connectionless network layer statistics--in our case,
308 * this is IP.
310 case CL_NL_ENTITY:
311 if (pcommand->toi_class == INFO_CLASS_GENERIC)
313 if (!pcbResponseInfoLen)
314 return ERROR_BAD_ENVIRONMENT;
315 *((ULONG *)pResponseInfo) = CL_NL_IP;
316 *pcbResponseInfoLen = sizeof(ULONG);
318 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
320 if (!pcbResponseInfoLen)
321 return ERROR_BAD_ENVIRONMENT;
322 if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
323 return ERROR_LOCK_VIOLATION;
324 GetIpStatistics(pResponseInfo);
326 *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
328 break;
330 /* Returns connectionless transport layer statistics--in our case,
331 * this is UDP.
333 case CL_TL_ENTITY:
334 if (pcommand->toi_class == INFO_CLASS_GENERIC)
336 if (!pcbResponseInfoLen)
337 return ERROR_BAD_ENVIRONMENT;
338 *((ULONG *)pResponseInfo) = CL_TL_UDP;
339 *pcbResponseInfoLen = sizeof(ULONG);
341 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
343 if (!pcbResponseInfoLen)
344 return ERROR_BAD_ENVIRONMENT;
345 if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS))
346 return ERROR_LOCK_VIOLATION;
347 GetUdpStatistics(pResponseInfo);
348 *pcbResponseInfoLen = sizeof(MIB_UDPSTATS);
350 break;
352 /* Returns connection-oriented transport layer statistics--in our
353 * case, this is TCP.
355 case CO_TL_ENTITY:
356 if (pcommand->toi_class == INFO_CLASS_GENERIC)
358 if (!pcbResponseInfoLen)
359 return ERROR_BAD_ENVIRONMENT;
360 *((ULONG *)pResponseInfo) = CO_TL_TCP;
361 *pcbResponseInfoLen = sizeof(ULONG);
363 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL)
365 if (!pcbResponseInfoLen)
366 return ERROR_BAD_ENVIRONMENT;
367 if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS))
368 return ERROR_LOCK_VIOLATION;
369 GetTcpStatistics(pResponseInfo);
370 *pcbResponseInfoLen = sizeof(MIB_TCPSTATS);
372 break;
374 default:
375 ERR("Unknown entity %ld for ENTITY_TYPE_ID query\n",
376 pcommand->toi_entity.tei_entity);
378 break;
380 /* This call returns the IP address, subnet mask, and broadcast
381 * address for an interface. If there are multiple IP addresses for
382 * the interface with the given index, returns the "first" one.
384 case IP_MIB_ADDRTABLE_ENTRY_ID:
386 DWORD index = pcommand->toi_entity.tei_instance;
387 PMIB_IPADDRROW baseIPInfo = pResponseInfo;
388 PMIB_IPADDRTABLE table;
389 DWORD tableSize, i;
391 if (!pcbResponseInfoLen)
392 return ERROR_BAD_ENVIRONMENT;
393 if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
394 return (ERROR_LOCK_VIOLATION);
396 /* get entire table, because there isn't an exported function that
397 gets just one entry. */
398 tableSize = 0;
399 GetIpAddrTable(NULL, &tableSize, FALSE);
400 table = HeapAlloc( GetProcessHeap(), 0, tableSize );
401 if (!table)
402 return ERROR_NOT_ENOUGH_MEMORY;
403 GetIpAddrTable(table, &tableSize, FALSE);
404 for (i = 0; i < table->dwNumEntries; i++)
406 if (table->table[i].dwIndex == index)
408 TRACE("Found IP info for tei_instance 0x%lx:\n", index);
409 TRACE("IP 0x%08lx, mask 0x%08lx\n", table->table[i].dwAddr,
410 table->table[i].dwMask);
411 *baseIPInfo = table->table[i];
412 break;
415 HeapFree( GetProcessHeap(), 0, table );
417 *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
418 break;
421 case IP_MIB_TABLE_ENTRY_ID:
423 switch (pcommand->toi_entity.tei_entity)
425 /* This call returns the routing table.
426 * No official documentation found, even the name of the command is unknown.
427 * Work is based on
428 * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
429 * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
430 * pcommand->toi_entity.tei_instance seems to be the interface number
431 * but route.exe outputs only the information for the last interface
432 * if only the routes for the pcommand->toi_entity.tei_instance
433 * interface are returned. */
434 case CL_NL_ENTITY:
436 DWORD routeTableSize, numRoutes, ndx, ret;
437 PMIB_IPFORWARDTABLE table;
438 IPRouteEntry *winRouteTable = pResponseInfo;
440 if (!pcbResponseInfoLen)
441 return ERROR_BAD_ENVIRONMENT;
442 ret = GetIpForwardTable(NULL, &routeTableSize, FALSE);
443 if (ret != ERROR_INSUFFICIENT_BUFFER)
444 return ret;
445 numRoutes = (routeTableSize - sizeof(MIB_IPFORWARDTABLE))
446 / sizeof(MIB_IPFORWARDROW) + 1;
447 if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
448 return (ERROR_LOCK_VIOLATION);
449 table = HeapAlloc( GetProcessHeap(), 0, 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;
458 memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
459 for (ndx = 0; ndx < table->dwNumEntries; ndx++)
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++;
478 /* calculate the length of the data in the output buffer */
479 *pcbResponseInfoLen = sizeof(IPRouteEntry) *
480 table->dwNumEntries;
482 HeapFree( GetProcessHeap(), 0, table );
484 break;
486 case AT_ARP:
488 DWORD arpTableSize, numEntries, ret;
489 PMIB_IPNETTABLE table;
491 if (!pcbResponseInfoLen)
492 return ERROR_BAD_ENVIRONMENT;
493 ret = GetIpNetTable(NULL, &arpTableSize, FALSE);
494 if (ret != ERROR_INSUFFICIENT_BUFFER)
495 return ret;
496 numEntries = (arpTableSize - sizeof(MIB_IPNETTABLE))
497 / sizeof(MIB_IPNETROW) + 1;
498 if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * numEntries)
499 return (ERROR_LOCK_VIOLATION);
500 table = HeapAlloc( GetProcessHeap(), 0, arpTableSize );
501 if (!table)
502 return ERROR_NOT_ENOUGH_MEMORY;
503 ret = GetIpNetTable(table, &arpTableSize, FALSE);
504 if (ret != NO_ERROR) {
505 HeapFree( GetProcessHeap(), 0, table );
506 return ret;
508 if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) *
509 table->dwNumEntries)
511 HeapFree( GetProcessHeap(), 0, table );
512 return ERROR_LOCK_VIOLATION;
514 memcpy(pResponseInfo, table->table, sizeof(MIB_IPNETROW) *
515 table->dwNumEntries);
517 /* calculate the length of the data in the output buffer */
518 *pcbResponseInfoLen = sizeof(MIB_IPNETROW) *
519 table->dwNumEntries;
521 HeapFree( GetProcessHeap(), 0, table );
523 break;
525 case CO_TL_ENTITY:
527 DWORD tcpTableSize, numEntries, ret;
528 PMIB_TCPTABLE table;
529 DWORD i;
531 if (!pcbResponseInfoLen)
532 return ERROR_BAD_ENVIRONMENT;
533 ret = GetTcpTable(NULL, &tcpTableSize, FALSE);
534 if (ret != ERROR_INSUFFICIENT_BUFFER)
535 return ret;
536 numEntries = (tcpTableSize - sizeof(MIB_TCPTABLE))
537 / sizeof(MIB_TCPROW) + 1;
538 if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * numEntries)
539 return (ERROR_LOCK_VIOLATION);
540 table = HeapAlloc( GetProcessHeap(), 0, tcpTableSize );
541 if (!table)
542 return ERROR_NOT_ENOUGH_MEMORY;
543 ret = GetTcpTable(table, &tcpTableSize, FALSE);
544 if (ret != NO_ERROR) {
545 HeapFree( GetProcessHeap(), 0, table );
546 return ret;
548 if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) *
549 table->dwNumEntries)
551 HeapFree( GetProcessHeap(), 0, table );
552 return ERROR_LOCK_VIOLATION;
554 for (i = 0; i < table->dwNumEntries; i++)
556 USHORT sPort;
558 sPort = ntohs((USHORT)table->table[i].dwLocalPort);
559 table->table[i].dwLocalPort = (DWORD)sPort;
560 sPort = ntohs((USHORT)table->table[i].dwRemotePort);
561 table->table[i].dwRemotePort = (DWORD)sPort;
563 memcpy(pResponseInfo, table->table, sizeof(MIB_TCPROW) *
564 table->dwNumEntries);
566 /* calculate the length of the data in the output buffer */
567 *pcbResponseInfoLen = sizeof(MIB_TCPROW) *
568 table->dwNumEntries;
570 HeapFree( GetProcessHeap(), 0, table );
572 break;
574 default:
576 FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
577 pcommand->toi_id, pcommand->toi_entity.tei_entity,
578 pcommand->toi_entity.tei_instance, pcommand->toi_class);
580 return (ERROR_BAD_ENVIRONMENT);
584 break;
587 default:
589 FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n",
590 pcommand->toi_id, pcommand->toi_entity.tei_entity,
591 pcommand->toi_entity.tei_instance, pcommand->toi_class);
593 return (ERROR_BAD_ENVIRONMENT);
597 break;
600 case WSCNTL_TCPIP_ICMP_ECHO:
602 unsigned int addr = *(unsigned int*)pRequestInfo;
603 #if 0
604 int timeout= *(unsigned int*)(inbuf+4);
605 short x1 = *(unsigned short*)(inbuf+8);
606 short sendbufsize = *(unsigned short*)(inbuf+10);
607 char x2 = *(unsigned char*)(inbuf+12);
608 char ttl = *(unsigned char*)(inbuf+13);
609 char service = *(unsigned char*)(inbuf+14);
610 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
611 #endif
613 FIXME("(ICMP_ECHO) to 0x%08x stub\n", addr);
614 break;
617 default:
618 FIXME("Protocol Not Supported -> protocol=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
619 protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
621 return (WSAEOPNOTSUPP);
625 return (WSCTL_SUCCESS);
630 /***********************************************************************
631 * WSARecvEx (WSOCK32.1107)
633 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
634 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
635 * into the flags parameter when a partial packet is read. This only applies to
636 * sockets using the datagram protocol. This method does not seem to be implemented
637 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
638 * flag when a fragmented packet arrives.
640 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
642 FIXME("(WSARecvEx) partial packet return value not set\n");
643 return recv(s, buf, len, *flags);
647 /***********************************************************************
648 * s_perror (WSOCK32.1108)
650 void WINAPI s_perror(LPCSTR message)
652 FIXME("(%s): stub\n",message);
653 return;