xref: /reactos/dll/win32/wshtcpip/wshtcpip.c (revision 9cfd8dd9)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock Helper DLL for TCP/IP
4  * FILE:        wshtcpip.c
5  * PURPOSE:     DLL entry
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/09-2000 Created
9  */
10 #include "wshtcpip.h"
11 #define NDEBUG
12 #include <debug.h>
13 
14 BOOL
15 EXPORT
16 DllMain(HANDLE hInstDll,
17         ULONG dwReason,
18         PVOID Reserved)
19 {
20     DPRINT("DllMain of wshtcpip.dll\n");
21 
22     switch (dwReason) {
23     case DLL_PROCESS_ATTACH:
24         /* Don't need thread attach notifications
25            so disable them to improve performance */
26         DisableThreadLibraryCalls(hInstDll);
27         break;
28 
29     case DLL_THREAD_ATTACH:
30         break;
31 
32     case DLL_THREAD_DETACH:
33         break;
34 
35     case DLL_PROCESS_DETACH:
36         break;
37     }
38     return TRUE;
39 }
40 
41 
42 INT
43 EXPORT
44 WSHAddressToString(
45     IN      LPSOCKADDR Address,
46     IN      INT AddressLength,
47     IN      LPWSAPROTOCOL_INFOW ProtocolInfo    OPTIONAL,
48     OUT     LPWSTR AddressString,
49     IN OUT  LPDWORD AddressStringLength)
50 {
51     UNIMPLEMENTED;
52 
53     return NO_ERROR;
54 }
55 
56 
57 INT
58 EXPORT
59 WSHEnumProtocols(
60     IN      LPINT lpiProtocols  OPTIONAL,
61     IN      LPWSTR lpTransportKeyName,
62     IN OUT  LPVOID lpProtocolBuffer,
63     IN OUT  LPDWORD lpdwBufferLength)
64 {
65     UNIMPLEMENTED;
66 
67     return NO_ERROR;
68 }
69 
70 
71 INT
72 EXPORT
73 WSHGetBroadcastSockaddr(
74     IN  PVOID HelperDllSocketContext,
75     OUT PSOCKADDR Sockaddr,
76     OUT PINT SockaddrLength)
77 {
78     INT Size = 2 * sizeof(UINT);
79 
80     if (*SockaddrLength < Size)
81     {
82         DPRINT1("Socket address length too small: %d\n", *SockaddrLength);
83         return WSAEFAULT;
84     }
85 
86     RtlZeroMemory(Sockaddr, *SockaddrLength);
87 
88     Sockaddr->sa_family = AF_INET;
89     *((PUINT)Sockaddr->sa_data) = INADDR_BROADCAST;
90 
91     /* *SockaddrLength = Size; */
92 
93     return NO_ERROR;
94 }
95 
96 
97 INT
98 EXPORT
99 WSHGetProviderGuid(
100     IN  LPWSTR ProviderName,
101     OUT LPGUID ProviderGuid)
102 {
103     UNIMPLEMENTED;
104 
105     return NO_ERROR;
106 }
107 
108 
109 /*
110 Document from OSR how WSHGetSockaddrType works
111 http://www.osronline.com/ddkx/network/37wshfun_5lyq.htm
112 */
113 
114 INT
115 EXPORT
116 WSHGetSockaddrType(
117     IN  PSOCKADDR Sockaddr,
118     IN  DWORD SockaddrLength,
119     OUT PSOCKADDR_INFO SockaddrInfo)
120 {
121     PSOCKADDR_IN ipv4 = (PSOCKADDR_IN)Sockaddr;
122 
123     if (!ipv4 || !SockaddrInfo || SockaddrLength < sizeof(SOCKADDR_IN) ||
124         ipv4->sin_family != AF_INET)
125     {
126         DPRINT1("Invalid parameter: %x %x %d %u\n", ipv4, SockaddrInfo, SockaddrLength, (ipv4 ? ipv4->sin_family : 0));
127         return WSAEINVAL;
128     }
129 
130     switch (ntohl(ipv4->sin_addr.s_addr))
131     {
132       case INADDR_ANY:
133            SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
134            break;
135 
136       case INADDR_BROADCAST:
137            SockaddrInfo->AddressInfo = SockaddrAddressInfoBroadcast;
138            break;
139 
140       case INADDR_LOOPBACK:
141            SockaddrInfo->AddressInfo = SockaddrAddressInfoLoopback;
142            break;
143 
144       default:
145            SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
146 	   break;
147     }
148 
149     if (ntohs(ipv4->sin_port) == 0)
150  	SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
151     else if (ntohs(ipv4->sin_port) < IPPORT_RESERVED)
152 	SockaddrInfo->EndpointInfo = SockaddrEndpointInfoReserved;
153     else
154         SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
155 
156     return NO_ERROR;
157 }
158 
159 static
160 void
161 GetTdiTypeId(
162     _In_ INT Level,
163     _In_ INT OptionName,
164     _Out_ PULONG TdiType,
165     _Out_ PULONG TdiId)
166 {
167     switch (Level)
168     {
169        case SOL_SOCKET:
170           *TdiType = INFO_TYPE_ADDRESS_OBJECT;
171           switch (OptionName)
172           {
173              case SO_KEEPALIVE:
174                 /* FIXME: Return proper option */
175                 ASSERT(FALSE);
176                 break;
177              default:
178                 break;
179           }
180           break;
181 
182        case IPPROTO_IP:
183           *TdiType = INFO_TYPE_ADDRESS_OBJECT;
184           switch (OptionName)
185           {
186              case IP_TTL:
187                 *TdiId = AO_OPTION_TTL;
188                 return;
189 
190              case IP_DONTFRAGMENT:
191                  *TdiId = AO_OPTION_IP_DONTFRAGMENT;
192                  return;
193 
194 #if 0
195              case IP_RECEIVE_BROADCAST:
196                  *TdiId = AO_OPTION_BROADCAST;
197                  return;
198 #endif
199 
200              case IP_HDRINCL:
201                  *TdiId = AO_OPTION_IP_HDRINCL;
202                  return;
203 
204              default:
205                 break;
206           }
207           break;
208 
209        case IPPROTO_TCP:
210           *TdiType = INFO_TYPE_CONNECTION;
211           switch (OptionName)
212           {
213              case TCP_NODELAY:
214                  *TdiId = TCP_SOCKET_NODELAY;
215                  return;
216              default:
217                  break;
218           }
219 
220        default:
221           break;
222     }
223 
224     DPRINT1("Unknown level/option name: %d %d\n", Level, OptionName);
225     *TdiType = 0;
226     *TdiId = 0;
227 }
228 
229 INT
230 EXPORT
231 WSHGetSocketInformation(
232     IN  PVOID HelperDllSocketContext,
233     IN  SOCKET SocketHandle,
234     IN  HANDLE TdiAddressObjectHandle,
235     IN  HANDLE TdiConnectionObjectHandle,
236     IN  INT Level,
237     IN  INT OptionName,
238     OUT PCHAR OptionValue,
239     OUT LPINT OptionLength)
240 {
241     UNIMPLEMENTED;
242 
243     DPRINT1("Get: Unknown level/option name: %d %d\n", Level, OptionName);
244 
245     *OptionLength = 0;
246 
247     return NO_ERROR;
248 }
249 
250 
251 INT
252 EXPORT
253 WSHGetWildcardSockaddr(
254     IN  PVOID HelperDllSocketContext,
255     OUT PSOCKADDR Sockaddr,
256     OUT PINT SockaddrLength)
257 {
258     INT Size = 2 * sizeof(UINT);
259 
260     if (*SockaddrLength < Size)
261     {
262         DPRINT1("Socket address length too small: %d\n", *SockaddrLength);
263         return WSAEFAULT;
264     }
265 
266     RtlZeroMemory(Sockaddr, *SockaddrLength);
267 
268     Sockaddr->sa_family = AF_INET;
269     *((PUINT)Sockaddr->sa_data) = INADDR_ANY;
270 
271     /* *SockaddrLength = Size; */
272 
273     return NO_ERROR;
274 }
275 
276 
277 DWORD
278 EXPORT
279 WSHGetWinsockMapping(
280     OUT PWINSOCK_MAPPING Mapping,
281     IN  DWORD MappingLength)
282 {
283     DWORD Rows = 6;
284     DWORD Columns = 3;
285     DWORD Size = 2 * sizeof(DWORD) + Columns * Rows * sizeof(DWORD);
286 
287     if (MappingLength < Size)
288     {
289         DPRINT1("Mapping length too small: %d\n", MappingLength);
290         return Size;
291     }
292 
293     Mapping->Rows = Rows;
294     Mapping->Columns = Columns;
295 
296     Mapping->Mapping[0].AddressFamily = AF_INET;
297     Mapping->Mapping[0].SocketType = SOCK_STREAM;
298     Mapping->Mapping[0].Protocol = 0;
299 
300     Mapping->Mapping[1].AddressFamily = AF_INET;
301     Mapping->Mapping[1].SocketType = SOCK_STREAM;
302     Mapping->Mapping[1].Protocol = IPPROTO_TCP;
303 
304     Mapping->Mapping[2].AddressFamily = AF_INET;
305     Mapping->Mapping[2].SocketType = SOCK_DGRAM;
306     Mapping->Mapping[2].Protocol = 0;
307 
308     Mapping->Mapping[3].AddressFamily = AF_INET;
309     Mapping->Mapping[3].SocketType = SOCK_DGRAM;
310     Mapping->Mapping[3].Protocol = IPPROTO_UDP;
311 
312     Mapping->Mapping[4].AddressFamily = AF_INET;
313     Mapping->Mapping[4].SocketType = SOCK_RAW;
314     Mapping->Mapping[4].Protocol = 0;
315 
316     Mapping->Mapping[5].AddressFamily = AF_INET;
317     Mapping->Mapping[5].SocketType = SOCK_RAW;
318     Mapping->Mapping[5].Protocol = IPPROTO_ICMP;
319 
320     return NO_ERROR;
321 }
322 
323 
324 INT
325 EXPORT
326 WSHGetWSAProtocolInfo(
327     IN  LPWSTR ProviderName,
328     OUT LPWSAPROTOCOL_INFOW *ProtocolInfo,
329     OUT LPDWORD ProtocolInfoEntries)
330 {
331     UNIMPLEMENTED;
332 
333     return NO_ERROR;
334 }
335 
336 
337 INT
338 EXPORT
339 WSHIoctl(
340     IN  PVOID HelperDllSocketContext,
341     IN  SOCKET SocketHandle,
342     IN  HANDLE TdiAddressObjectHandle,
343     IN  HANDLE TdiConnectionObjectHandle,
344     IN  DWORD IoControlCode,
345     IN  LPVOID InputBuffer,
346     IN  DWORD InputBufferLength,
347     IN  LPVOID OutputBuffer,
348     IN  DWORD OutputBufferLength,
349     OUT LPDWORD NumberOfBytesReturned,
350     IN  LPWSAOVERLAPPED Overlapped,
351     IN  LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
352     OUT LPBOOL NeedsCompletion)
353 {
354     INT res;
355 
356     if (IoControlCode == SIO_GET_INTERFACE_LIST)
357     {
358         res = WSHIoctl_GetInterfaceList(
359             OutputBuffer,
360             OutputBufferLength,
361             NumberOfBytesReturned,
362             NeedsCompletion);
363         return res;
364     }
365 
366     UNIMPLEMENTED;
367 
368     DPRINT1("Ioctl: Unknown IOCTL code: %x\n", IoControlCode);
369 
370     return WSAEINVAL;
371 }
372 
373 
374 INT
375 EXPORT
376 WSHJoinLeaf(
377     IN  PVOID HelperDllSocketContext,
378     IN  SOCKET SocketHandle,
379     IN  HANDLE TdiAddressObjectHandle,
380     IN  HANDLE TdiConnectionObjectHandle,
381     IN  PVOID LeafHelperDllSocketContext,
382     IN  SOCKET LeafSocketHandle,
383     IN  PSOCKADDR Sockaddr,
384     IN  DWORD SockaddrLength,
385     IN  LPWSABUF CallerData,
386     IN  LPWSABUF CalleeData,
387     IN  LPQOS SocketQOS,
388     IN  LPQOS GroupQOS,
389     IN  DWORD Flags)
390 {
391     UNIMPLEMENTED;
392 
393     return NO_ERROR;
394 }
395 
396 INT
397 SendRequest(
398     IN PVOID Request,
399     IN DWORD RequestSize,
400     IN DWORD IOCTL)
401 {
402     BOOLEAN Success;
403     HANDLE TcpCC;
404     DWORD BytesReturned;
405 
406     if (openTcpFile(&TcpCC, FILE_READ_DATA | FILE_WRITE_DATA) != STATUS_SUCCESS)
407         return WSAEINVAL;
408 
409     Success = DeviceIoControl(TcpCC,
410                               IOCTL,
411                               Request,
412                               RequestSize,
413                               NULL,
414                               0,
415                               &BytesReturned,
416                               NULL);
417 
418     closeTcpFile(TcpCC);
419 
420     DPRINT("DeviceIoControl: %ld\n", (Success ? NO_ERROR : GetLastError()));
421 
422     if (!Success)
423         return WSAEINVAL;
424 
425     return NO_ERROR;
426 }
427 
428 INT
429 EXPORT
430 WSHNotify(
431     IN  PVOID HelperDllSocketContext,
432     IN  SOCKET SocketHandle,
433     IN  HANDLE TdiAddressObjectHandle,
434     IN  HANDLE TdiConnectionObjectHandle,
435     IN  DWORD NotifyEvent)
436 {
437     PSOCKET_CONTEXT Context = HelperDllSocketContext;
438     NTSTATUS Status;
439     HANDLE TcpCC;
440     TDIEntityID *EntityIDs;
441     DWORD EntityCount, i;
442     PQUEUED_REQUEST QueuedRequest, NextQueuedRequest;
443 
444     switch (NotifyEvent)
445     {
446         case WSH_NOTIFY_CLOSE:
447             DPRINT("WSHNotify: WSH_NOTIFY_CLOSE\n");
448             QueuedRequest = Context->RequestQueue;
449             while (QueuedRequest)
450             {
451                 NextQueuedRequest = QueuedRequest->Next;
452 
453                 HeapFree(GetProcessHeap(), 0, QueuedRequest->Info);
454                 HeapFree(GetProcessHeap(), 0, QueuedRequest);
455 
456                 QueuedRequest = NextQueuedRequest;
457             }
458             HeapFree(GetProcessHeap(), 0, HelperDllSocketContext);
459             break;
460 
461 
462         case WSH_NOTIFY_BIND:
463             DPRINT("WSHNotify: WSH_NOTIFY_BIND\n");
464             Status = openTcpFile(&TcpCC, FILE_READ_DATA);
465             if (Status != STATUS_SUCCESS)
466                 return WSAEINVAL;
467 
468             Status = tdiGetEntityIDSet(TcpCC,
469                                        &EntityIDs,
470                                        &EntityCount);
471 
472             closeTcpFile(TcpCC);
473 
474             if (Status != STATUS_SUCCESS)
475                 return WSAEINVAL;
476 
477             for (i = 0; i < EntityCount; i++)
478             {
479                 if (EntityIDs[i].tei_entity == CO_TL_ENTITY ||
480                     EntityIDs[i].tei_entity == CL_TL_ENTITY ||
481                     EntityIDs[i].tei_entity == ER_ENTITY)
482                 {
483                     Context->AddrFileInstance = EntityIDs[i].tei_instance;
484                     Context->AddrFileEntityType = EntityIDs[i].tei_entity;
485                 }
486             }
487 
488             DPRINT("Instance: %lx Type: %lx\n", Context->AddrFileInstance, Context->AddrFileEntityType);
489 
490             tdiFreeThingSet(EntityIDs);
491 
492             Context->SocketState = SocketStateBound;
493 
494             QueuedRequest = Context->RequestQueue;
495             while (QueuedRequest)
496             {
497                 QueuedRequest->Info->ID.toi_entity.tei_entity = Context->AddrFileEntityType;
498                 QueuedRequest->Info->ID.toi_entity.tei_instance = Context->AddrFileInstance;
499 
500                 SendRequest(QueuedRequest->Info,
501                             sizeof(*QueuedRequest->Info) + QueuedRequest->Info->BufferSize,
502                             IOCTL_TCP_SET_INFORMATION_EX);
503 
504                 NextQueuedRequest = QueuedRequest->Next;
505 
506                 HeapFree(GetProcessHeap(), 0, QueuedRequest->Info);
507                 HeapFree(GetProcessHeap(), 0, QueuedRequest);
508 
509                 QueuedRequest = NextQueuedRequest;
510             }
511             Context->RequestQueue = NULL;
512             break;
513 
514         default:
515             DPRINT1("Unwanted notification received! (%ld)\n", NotifyEvent);
516             break;
517     }
518 
519     return NO_ERROR;
520 }
521 
522 
523 INT
524 EXPORT
525 WSHOpenSocket(
526     IN OUT  PINT AddressFamily,
527     IN OUT  PINT SocketType,
528     IN OUT  PINT Protocol,
529     OUT     PUNICODE_STRING TransportDeviceName,
530     OUT     PVOID HelperDllSocketContext,
531     OUT     PDWORD NotificationEvents)
532 /*
533  * FUNCTION: Opens a socket
534  */
535 {
536     return WSHOpenSocket2(AddressFamily,
537                           SocketType,
538                           Protocol,
539                           0,
540                           0,
541                           TransportDeviceName,
542                           HelperDllSocketContext,
543                           NotificationEvents);
544 }
545 
546 
547 INT
548 EXPORT
549 WSHOpenSocket2(
550     OUT PINT AddressFamily,
551     IN  OUT PINT SocketType,
552     IN  OUT PINT Protocol,
553     IN  GROUP Group,
554     IN  DWORD Flags,
555     OUT PUNICODE_STRING TransportDeviceName,
556     OUT PVOID *HelperDllSocketContext,
557     OUT PDWORD NotificationEvents)
558 /*
559  * FUNCTION: Opens a socket
560  * ARGUMENTS:
561  *     AddressFamily          = Address of buffer with address family (updated)
562  *     SocketType             = Address of buffer with type of socket (updated)
563  *     Protocol               = Address of buffer with protocol number (updated)
564  *     Group                  = Socket group
565  *     Flags                  = Socket flags
566  *     TransportDeviceName    = Address of buffer to place name of transport device
567  *     HelperDllSocketContext = Address of buffer to place socket context pointer
568  *     NotificationEvents     = Address of buffer to place flags for event notification
569  * RETURNS:
570  *     Status of operation
571  * NOTES:
572  *     Mapping tripple is returned in an canonicalized form
573  */
574 {
575     PSOCKET_CONTEXT Context;
576     UNICODE_STRING String;
577     UNICODE_STRING TcpDeviceName = RTL_CONSTANT_STRING(DD_TCP_DEVICE_NAME);
578     UNICODE_STRING UdpDeviceName = RTL_CONSTANT_STRING(DD_UDP_DEVICE_NAME);
579     UNICODE_STRING RawDeviceName = RTL_CONSTANT_STRING(DD_RAW_IP_DEVICE_NAME);
580 
581     DPRINT("WSHOpenSocket2 called\n");
582 
583     switch (*SocketType) {
584     case SOCK_STREAM:
585         String = TcpDeviceName;
586         break;
587 
588     case SOCK_DGRAM:
589         String = UdpDeviceName;
590         break;
591 
592     case SOCK_RAW:
593         if ((*Protocol < 0) || (*Protocol > 255))
594           return WSAEINVAL;
595 
596         String = RawDeviceName;
597         break;
598 
599     default:
600         return WSAEINVAL;
601     }
602 
603     RtlInitUnicodeString(TransportDeviceName, NULL);
604 
605     TransportDeviceName->MaximumLength = String.Length +        /* Transport device name */
606                                          (4 * sizeof(WCHAR) +   /* Separator and protocol */
607                                          sizeof(UNICODE_NULL)); /* Terminating null */
608 
609     TransportDeviceName->Buffer = HeapAlloc(
610         GetProcessHeap(),
611         0,
612         TransportDeviceName->MaximumLength);
613 
614     if (!TransportDeviceName->Buffer)
615         return WSAENOBUFS;
616 
617     /* Append the transport device name */
618     RtlAppendUnicodeStringToString(TransportDeviceName, &String);
619 
620     if (*SocketType == SOCK_RAW) {
621         /* Append a separator */
622         TransportDeviceName->Buffer[TransportDeviceName->Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
623         TransportDeviceName->Length += sizeof(WCHAR);
624         TransportDeviceName->Buffer[TransportDeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL;
625 
626         /* Append the protocol number */
627         String.Buffer = TransportDeviceName->Buffer + (TransportDeviceName->Length / sizeof(WCHAR));
628         String.Length = 0;
629         String.MaximumLength = TransportDeviceName->MaximumLength - TransportDeviceName->Length;
630 
631         RtlIntegerToUnicodeString((ULONG)*Protocol, 10, &String);
632 
633         TransportDeviceName->Length += String.Length;
634     }
635 
636     /* Setup a socket context area */
637 
638     Context = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOCKET_CONTEXT));
639     if (!Context) {
640         RtlFreeUnicodeString(TransportDeviceName);
641         return WSAENOBUFS;
642     }
643 
644     Context->AddressFamily = *AddressFamily;
645     Context->SocketType    = *SocketType;
646     Context->Protocol      = *Protocol;
647     Context->Flags         = Flags;
648     Context->SocketState   = SocketStateCreated;
649 
650     *HelperDllSocketContext = Context;
651     *NotificationEvents = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND;
652 
653     return NO_ERROR;
654 }
655 
656 INT
657 EXPORT
658 WSHSetSocketInformation(
659     IN  PVOID HelperDllSocketContext,
660     IN  SOCKET SocketHandle,
661     IN  HANDLE TdiAddressObjectHandle,
662     IN  HANDLE TdiConnectionObjectHandle,
663     IN  INT Level,
664     IN  INT OptionName,
665     IN  PCHAR OptionValue,
666     IN  INT OptionLength)
667 {
668     PSOCKET_CONTEXT Context = HelperDllSocketContext;
669     ULONG TdiType, TdiId;
670     INT Status;
671     PTCP_REQUEST_SET_INFORMATION_EX Info;
672     PQUEUED_REQUEST Queued, NextQueued;
673 
674     DPRINT("WSHSetSocketInformation\n");
675 
676     /* FIXME: We only handle address file object here */
677 
678     switch (Level)
679     {
680         case SOL_SOCKET:
681             switch (OptionName)
682             {
683                 case SO_DONTROUTE:
684                     if (OptionLength < sizeof(BOOL))
685                     {
686                         return WSAEFAULT;
687                     }
688                     Context->DontRoute = *(BOOL*)OptionValue;
689                     /* This is silently ignored on Windows */
690                     return 0;
691 
692                 case SO_KEEPALIVE:
693                     /* FIXME -- We'll send this to TCPIP */
694                     DPRINT1("Set: SO_KEEPALIVE not yet supported\n");
695                     return 0;
696 
697                 default:
698                     /* Invalid option */
699                     DPRINT1("Set: Received unexpected SOL_SOCKET option %d\n", OptionName);
700                     return WSAENOPROTOOPT;
701             }
702             break;
703 
704         case IPPROTO_IP:
705             switch (OptionName)
706             {
707                 case IP_TTL:
708                 case IP_DONTFRAGMENT:
709                 case IP_HDRINCL:
710                     /* Send these to TCPIP */
711                     break;
712 
713                 default:
714                     /* Invalid option -- FIXME */
715                     DPRINT1("Set: Received unsupported IPPROTO_IP option %d\n", OptionName);
716                     return 0;
717             }
718             break;
719 
720         case IPPROTO_TCP:
721             switch (OptionName)
722             {
723                 case TCP_NODELAY:
724                     if (OptionLength < sizeof(CHAR))
725                     {
726                         return WSAEFAULT;
727                     }
728                     break;
729 
730                 default:
731                     /* Invalid option */
732                     DPRINT1("Set: Received unexpected IPPROTO_TCP option %d\n", OptionName);
733                     return 0;
734             }
735             break;
736 
737         default:
738             DPRINT1("Set: Received unexpected %d option %d\n", Level, OptionName);
739             return 0;
740     }
741 
742     /* If we get here, GetAddressOption must return something valid */
743     GetTdiTypeId(Level, OptionName, &TdiType, &TdiId);
744     ASSERT((TdiId != 0) && (TdiType != 0));
745 
746     Info = HeapAlloc(GetProcessHeap(), 0, sizeof(*Info) + OptionLength);
747     if (!Info)
748         return WSAENOBUFS;
749 
750     Info->ID.toi_entity.tei_entity = Context->AddrFileEntityType;
751     Info->ID.toi_entity.tei_instance = Context->AddrFileInstance;
752     Info->ID.toi_class = INFO_CLASS_PROTOCOL;
753     Info->ID.toi_type = TdiType;
754     Info->ID.toi_id = TdiId;
755     Info->BufferSize = OptionLength;
756     memcpy(Info->Buffer, OptionValue, OptionLength);
757 
758     if (Context->SocketState == SocketStateCreated)
759     {
760         if (Context->RequestQueue)
761         {
762             Queued = Context->RequestQueue;
763             while ((NextQueued = Queued->Next))
764             {
765                Queued = NextQueued;
766             }
767 
768             Queued->Next = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUED_REQUEST));
769             if (!Queued->Next)
770             {
771                 HeapFree(GetProcessHeap(), 0, Info);
772                 return WSAENOBUFS;
773             }
774 
775             NextQueued = Queued->Next;
776             NextQueued->Next = NULL;
777             NextQueued->Info = Info;
778         }
779         else
780         {
781             Context->RequestQueue = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUED_REQUEST));
782             if (!Context->RequestQueue)
783             {
784                 HeapFree(GetProcessHeap(), 0, Info);
785                 return WSAENOBUFS;
786             }
787 
788             Context->RequestQueue->Next = NULL;
789             Context->RequestQueue->Info = Info;
790         }
791 
792         return 0;
793     }
794 
795     Status = SendRequest(Info, sizeof(*Info) + Info->BufferSize, IOCTL_TCP_SET_INFORMATION_EX);
796 
797     HeapFree(GetProcessHeap(), 0, Info);
798 
799     return Status;
800 }
801 
802 
803 INT
804 EXPORT
805 WSHStringToAddress(
806     IN      LPWSTR AddressString,
807     IN      DWORD AddressFamily,
808     IN      LPWSAPROTOCOL_INFOW ProtocolInfo    OPTIONAL,
809     OUT     LPSOCKADDR Address,
810     IN OUT  LPDWORD AddressStringLength)
811 {
812     UNIMPLEMENTED;
813 
814     return NO_ERROR;
815 }
816 
817 /* EOF */
818