Merge aicom-network-branch (without NDIS changes for now)
[reactos.git] / reactos / dll / win32 / wshtcpip / wshtcpip.c
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 DWORD 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 UINT
160 GetAddressOption(INT Level, INT OptionName)
161 {
162 switch (Level)
163 {
164 case IPPROTO_IP:
165 switch (OptionName)
166 {
167 case IP_TTL:
168 return AO_OPTION_TTL;
169
170 case IP_DONTFRAGMENT:
171 return AO_OPTION_IP_DONTFRAGMENT;
172
173 #if 0
174 case IP_RECEIVE_BROADCAST:
175 return AO_OPTION_BROADCAST;
176 #endif
177
178 case IP_HDRINCL:
179 return AO_OPTION_IP_HDRINCL;
180
181 default:
182 DPRINT1("Unknown option name for IPPROTO_IP: %d\n", OptionName);
183 return 0;
184 }
185 break;
186
187 default:
188 DPRINT1("Unknown level: %d\n", Level);
189 return 0;
190 }
191 }
192
193 INT
194 EXPORT
195 WSHGetSocketInformation(
196 IN PVOID HelperDllSocketContext,
197 IN SOCKET SocketHandle,
198 IN HANDLE TdiAddressObjectHandle,
199 IN HANDLE TdiConnectionObjectHandle,
200 IN INT Level,
201 IN INT OptionName,
202 OUT PCHAR OptionValue,
203 OUT LPINT OptionLength)
204 {
205 UNIMPLEMENTED
206
207 return NO_ERROR;
208 }
209
210
211 INT
212 EXPORT
213 WSHGetWildcardSockaddr(
214 IN PVOID HelperDllSocketContext,
215 OUT PSOCKADDR Sockaddr,
216 OUT PINT SockaddrLength)
217 {
218 DWORD Size = 2 * sizeof(UINT);
219
220 if (*SockaddrLength < Size)
221 {
222 DPRINT1("Socket address length too small: %d\n", *SockaddrLength);
223 return WSAEFAULT;
224 }
225
226 RtlZeroMemory(Sockaddr, *SockaddrLength);
227
228 Sockaddr->sa_family = AF_INET;
229 *((PUINT)Sockaddr->sa_data) = INADDR_ANY;
230
231 /* *SockaddrLength = Size; */
232
233 return NO_ERROR;
234 }
235
236
237 DWORD
238 EXPORT
239 WSHGetWinsockMapping(
240 OUT PWINSOCK_MAPPING Mapping,
241 IN DWORD MappingLength)
242 {
243 DWORD Rows = 6;
244 DWORD Columns = 3;
245 DWORD Size = 2 * sizeof(DWORD) + Columns * Rows * sizeof(DWORD);
246
247 if (MappingLength < Size)
248 {
249 DPRINT1("Mapping length too small: %d\n", MappingLength);
250 return Size;
251 }
252
253 Mapping->Rows = Rows;
254 Mapping->Columns = Columns;
255
256 Mapping->Mapping[0].AddressFamily = AF_INET;
257 Mapping->Mapping[0].SocketType = SOCK_STREAM;
258 Mapping->Mapping[0].Protocol = 0;
259
260 Mapping->Mapping[1].AddressFamily = AF_INET;
261 Mapping->Mapping[1].SocketType = SOCK_STREAM;
262 Mapping->Mapping[1].Protocol = IPPROTO_TCP;
263
264 Mapping->Mapping[2].AddressFamily = AF_INET;
265 Mapping->Mapping[2].SocketType = SOCK_DGRAM;
266 Mapping->Mapping[2].Protocol = 0;
267
268 Mapping->Mapping[3].AddressFamily = AF_INET;
269 Mapping->Mapping[3].SocketType = SOCK_DGRAM;
270 Mapping->Mapping[3].Protocol = IPPROTO_UDP;
271
272 Mapping->Mapping[4].AddressFamily = AF_INET;
273 Mapping->Mapping[4].SocketType = SOCK_RAW;
274 Mapping->Mapping[4].Protocol = 0;
275
276 Mapping->Mapping[5].AddressFamily = AF_INET;
277 Mapping->Mapping[5].SocketType = SOCK_RAW;
278 Mapping->Mapping[5].Protocol = IPPROTO_ICMP;
279
280 return NO_ERROR;
281 }
282
283
284 INT
285 EXPORT
286 WSHGetWSAProtocolInfo(
287 IN LPWSTR ProviderName,
288 OUT LPWSAPROTOCOL_INFOW *ProtocolInfo,
289 OUT LPDWORD ProtocolInfoEntries)
290 {
291 UNIMPLEMENTED
292
293 return NO_ERROR;
294 }
295
296
297 INT
298 EXPORT
299 WSHIoctl(
300 IN PVOID HelperDllSocketContext,
301 IN SOCKET SocketHandle,
302 IN HANDLE TdiAddressObjectHandle,
303 IN HANDLE TdiConnectionObjectHandle,
304 IN DWORD IoControlCode,
305 IN LPVOID InputBuffer,
306 IN DWORD InputBufferLength,
307 IN LPVOID OutputBuffer,
308 IN DWORD OutputBufferLength,
309 OUT LPDWORD NumberOfBytesReturned,
310 IN LPWSAOVERLAPPED Overlapped,
311 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
312 OUT LPBOOL NeedsCompletion)
313 {
314 UNIMPLEMENTED
315
316 return NO_ERROR;
317 }
318
319
320 INT
321 EXPORT
322 WSHJoinLeaf(
323 IN PVOID HelperDllSocketContext,
324 IN SOCKET SocketHandle,
325 IN HANDLE TdiAddressObjectHandle,
326 IN HANDLE TdiConnectionObjectHandle,
327 IN PVOID LeafHelperDllSocketContext,
328 IN SOCKET LeafSocketHandle,
329 IN PSOCKADDR Sockaddr,
330 IN DWORD SockaddrLength,
331 IN LPWSABUF CallerData,
332 IN LPWSABUF CalleeData,
333 IN LPQOS SocketQOS,
334 IN LPQOS GroupQOS,
335 IN DWORD Flags)
336 {
337 UNIMPLEMENTED
338
339 return NO_ERROR;
340 }
341
342 INT
343 SendRequest(
344 IN PVOID Request,
345 IN DWORD RequestSize,
346 IN DWORD IOCTL)
347 {
348 BOOLEAN Status;
349 HANDLE TcpCC;
350 DWORD BytesReturned;
351
352 if (openTcpFile(&TcpCC) != STATUS_SUCCESS)
353 return WSAEINVAL;
354
355 Status = DeviceIoControl(TcpCC,
356 IOCTL,
357 Request,
358 RequestSize,
359 NULL,
360 0,
361 &BytesReturned,
362 NULL);
363
364 closeTcpFile(TcpCC);
365
366 DPRINT("DeviceIoControl: %d\n", ((Status == TRUE) ? 0 : GetLastError()));
367
368 if (!Status)
369 return WSAEINVAL;
370
371 return NO_ERROR;
372 }
373
374 INT
375 EXPORT
376 WSHNotify(
377 IN PVOID HelperDllSocketContext,
378 IN SOCKET SocketHandle,
379 IN HANDLE TdiAddressObjectHandle,
380 IN HANDLE TdiConnectionObjectHandle,
381 IN DWORD NotifyEvent)
382 {
383 PSOCKET_CONTEXT Context = HelperDllSocketContext;
384 NTSTATUS Status;
385 HANDLE TcpCC;
386 TDIEntityID *EntityIDs;
387 DWORD EntityCount, i;
388 PQUEUED_REQUEST QueuedRequest, NextQueuedRequest;
389
390 switch (NotifyEvent)
391 {
392 case WSH_NOTIFY_CLOSE:
393 DPRINT("WSHNotify: WSH_NOTIFY_CLOSE\n");
394 QueuedRequest = Context->RequestQueue;
395 while (QueuedRequest)
396 {
397 NextQueuedRequest = QueuedRequest->Next;
398
399 HeapFree(GetProcessHeap(), 0, QueuedRequest->Info);
400 HeapFree(GetProcessHeap(), 0, QueuedRequest);
401
402 QueuedRequest = NextQueuedRequest;
403 }
404 HeapFree(GetProcessHeap(), 0, HelperDllSocketContext);
405 break;
406
407
408 case WSH_NOTIFY_BIND:
409 DPRINT("WSHNotify: WSH_NOTIFY_BIND\n");
410 Status = openTcpFile(&TcpCC);
411 if (Status != STATUS_SUCCESS)
412 return WSAEINVAL;
413
414 Status = tdiGetEntityIDSet(TcpCC,
415 &EntityIDs,
416 &EntityCount);
417
418 closeTcpFile(TcpCC);
419
420 if (Status != STATUS_SUCCESS)
421 return WSAEINVAL;
422
423 for (i = 0; i < EntityCount; i++)
424 {
425 if (EntityIDs[i].tei_entity == CO_TL_ENTITY ||
426 EntityIDs[i].tei_entity == CL_TL_ENTITY ||
427 EntityIDs[i].tei_entity == ER_ENTITY)
428 {
429 Context->AddrFileInstance = EntityIDs[i].tei_instance;
430 Context->AddrFileEntityType = EntityIDs[i].tei_entity;
431 }
432 }
433
434 DPRINT("Instance: %x Type: %x\n", Context->AddrFileInstance, Context->AddrFileEntityType);
435
436 tdiFreeThingSet(EntityIDs);
437
438 Context->SocketState = SocketStateBound;
439
440 QueuedRequest = Context->RequestQueue;
441 while (QueuedRequest)
442 {
443 QueuedRequest->Info->ID.toi_entity.tei_entity = Context->AddrFileEntityType;
444 QueuedRequest->Info->ID.toi_entity.tei_instance = Context->AddrFileInstance;
445
446 SendRequest(QueuedRequest->Info,
447 sizeof(*QueuedRequest->Info) + QueuedRequest->Info->BufferSize,
448 IOCTL_TCP_SET_INFORMATION_EX);
449
450 NextQueuedRequest = QueuedRequest->Next;
451
452 HeapFree(GetProcessHeap(), 0, QueuedRequest->Info);
453 HeapFree(GetProcessHeap(), 0, QueuedRequest);
454
455 QueuedRequest = NextQueuedRequest;
456 }
457 Context->RequestQueue = NULL;
458 break;
459
460 default:
461 DPRINT1("Unwanted notification received! (%d)\n", NotifyEvent);
462 break;
463 }
464
465 return NO_ERROR;
466 }
467
468
469 INT
470 EXPORT
471 WSHOpenSocket(
472 IN OUT PINT AddressFamily,
473 IN OUT PINT SocketType,
474 IN OUT PINT Protocol,
475 OUT PUNICODE_STRING TransportDeviceName,
476 OUT PVOID HelperDllSocketContext,
477 OUT PDWORD NotificationEvents)
478 /*
479 * FUNCTION: Opens a socket
480 */
481 {
482 return WSHOpenSocket2(AddressFamily,
483 SocketType,
484 Protocol,
485 0,
486 0,
487 TransportDeviceName,
488 HelperDllSocketContext,
489 NotificationEvents);
490 }
491
492
493 INT
494 EXPORT
495 WSHOpenSocket2(
496 OUT PINT AddressFamily,
497 IN OUT PINT SocketType,
498 IN OUT PINT Protocol,
499 IN GROUP Group,
500 IN DWORD Flags,
501 OUT PUNICODE_STRING TransportDeviceName,
502 OUT PVOID *HelperDllSocketContext,
503 OUT PDWORD NotificationEvents)
504 /*
505 * FUNCTION: Opens a socket
506 * ARGUMENTS:
507 * AddressFamily = Address of buffer with address family (updated)
508 * SocketType = Address of buffer with type of socket (updated)
509 * Protocol = Address of buffer with protocol number (updated)
510 * Group = Socket group
511 * Flags = Socket flags
512 * TransportDeviceName = Address of buffer to place name of transport device
513 * HelperDllSocketContext = Address of buffer to place socket context pointer
514 * NotificationEvents = Address of buffer to place flags for event notification
515 * RETURNS:
516 * Status of operation
517 * NOTES:
518 * Mapping tripple is returned in an canonicalized form
519 */
520 {
521 PSOCKET_CONTEXT Context;
522 UNICODE_STRING String;
523 UNICODE_STRING TcpDeviceName = RTL_CONSTANT_STRING(DD_TCP_DEVICE_NAME);
524 UNICODE_STRING UdpDeviceName = RTL_CONSTANT_STRING(DD_UDP_DEVICE_NAME);
525 UNICODE_STRING RawDeviceName = RTL_CONSTANT_STRING(DD_RAW_IP_DEVICE_NAME);
526 NTSTATUS Status;
527
528 DPRINT("WSHOpenSocket2 called\n");
529
530 switch (*SocketType) {
531 case SOCK_STREAM:
532 String = TcpDeviceName;
533 break;
534
535 case SOCK_DGRAM:
536 String = UdpDeviceName;
537 break;
538
539 case SOCK_RAW:
540 if ((*Protocol < 0) || (*Protocol > 255))
541 return WSAEINVAL;
542
543 String = RawDeviceName;
544 break;
545
546 default:
547 return WSAEINVAL;
548 }
549
550 RtlInitUnicodeString(TransportDeviceName, NULL);
551
552 TransportDeviceName->MaximumLength = String.Length + /* Transport device name */
553 (4 * sizeof(WCHAR) + /* Separator and protocol */
554 sizeof(UNICODE_NULL)); /* Terminating null */
555
556 TransportDeviceName->Buffer = HeapAlloc(
557 GetProcessHeap(),
558 0,
559 TransportDeviceName->MaximumLength);
560
561 if (!TransportDeviceName->Buffer)
562 return WSAENOBUFS;
563
564 /* Append the transport device name */
565 Status = RtlAppendUnicodeStringToString(TransportDeviceName, &String);
566
567 if (*SocketType == SOCK_RAW) {
568 /* Append a separator */
569 TransportDeviceName->Buffer[TransportDeviceName->Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
570 TransportDeviceName->Length += sizeof(WCHAR);
571 TransportDeviceName->Buffer[TransportDeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL;
572
573 /* Append the protocol number */
574 String.Buffer = TransportDeviceName->Buffer + (TransportDeviceName->Length / sizeof(WCHAR));
575 String.Length = 0;
576 String.MaximumLength = TransportDeviceName->MaximumLength - TransportDeviceName->Length;
577
578 Status = RtlIntegerToUnicodeString((ULONG)*Protocol, 10, &String);
579
580 TransportDeviceName->Length += String.Length;
581 }
582
583 /* Setup a socket context area */
584
585 Context = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOCKET_CONTEXT));
586 if (!Context) {
587 RtlFreeUnicodeString(TransportDeviceName);
588 return WSAENOBUFS;
589 }
590
591 Context->AddressFamily = *AddressFamily;
592 Context->SocketType = *SocketType;
593 Context->Protocol = *Protocol;
594 Context->Flags = Flags;
595 Context->SocketState = SocketStateCreated;
596
597 *HelperDllSocketContext = Context;
598 *NotificationEvents = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND;
599
600 return NO_ERROR;
601 }
602
603 INT
604 EXPORT
605 WSHSetSocketInformation(
606 IN PVOID HelperDllSocketContext,
607 IN SOCKET SocketHandle,
608 IN HANDLE TdiAddressObjectHandle,
609 IN HANDLE TdiConnectionObjectHandle,
610 IN INT Level,
611 IN INT OptionName,
612 IN PCHAR OptionValue,
613 IN INT OptionLength)
614 {
615 PSOCKET_CONTEXT Context = HelperDllSocketContext;
616 UINT RealOptionName;
617 INT Status;
618 PTCP_REQUEST_SET_INFORMATION_EX Info;
619 PQUEUED_REQUEST Queued, NextQueued;
620
621 DPRINT("WSHSetSocketInformation\n");
622
623 /* FIXME: We only handle address file object here */
624
625 RealOptionName = GetAddressOption(Level, OptionName);
626 if (!RealOptionName)
627 return WSAEINVAL;
628
629 Info = HeapAlloc(GetProcessHeap(), 0, sizeof(*Info) + OptionLength);
630 if (!Info)
631 return WSAENOBUFS;
632
633 Info->ID.toi_entity.tei_entity = Context->AddrFileEntityType;
634 Info->ID.toi_entity.tei_instance = Context->AddrFileInstance;
635 Info->ID.toi_class = INFO_CLASS_PROTOCOL;
636 Info->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
637 Info->ID.toi_id = RealOptionName;
638 Info->BufferSize = OptionLength;
639 memcpy(Info->Buffer, OptionValue, OptionLength);
640
641 if (Context->SocketState == SocketStateCreated)
642 {
643 if (Context->RequestQueue)
644 {
645 Queued = Context->RequestQueue;
646 while ((NextQueued = Queued->Next))
647 {
648 Queued = NextQueued;
649 }
650
651 Queued->Next = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUED_REQUEST));
652 if (!Queued->Next)
653 {
654 HeapFree(GetProcessHeap(), 0, Info);
655 return WSAENOBUFS;
656 }
657
658 NextQueued = Queued->Next;
659 NextQueued->Next = NULL;
660 NextQueued->Info = Info;
661 }
662 else
663 {
664 Context->RequestQueue = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUED_REQUEST));
665 if (!Context->RequestQueue)
666 {
667 HeapFree(GetProcessHeap(), 0, Info);
668 return WSAENOBUFS;
669 }
670
671 Context->RequestQueue->Next = NULL;
672 Context->RequestQueue->Info = Info;
673 }
674
675 return 0;
676 }
677
678 Status = SendRequest(Info, sizeof(*Info) + Info->BufferSize, IOCTL_TCP_SET_INFORMATION_EX);
679
680 HeapFree(GetProcessHeap(), 0, Info);
681
682 return Status;
683 }
684
685
686 INT
687 EXPORT
688 WSHStringToAddress(
689 IN LPWSTR AddressString,
690 IN DWORD AddressFamily,
691 IN LPWSAPROTOCOL_INFOW ProtocolInfo OPTIONAL,
692 OUT LPSOCKADDR Address,
693 IN OUT LPDWORD AddressStringLength)
694 {
695 UNIMPLEMENTED
696
697 return NO_ERROR;
698 }
699
700 /* EOF */