1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite for TCPIP.sys
5  * PROGRAMMER:      Jérôme Gardou <jerome.gardou@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include <tdikrnl.h>
10 #include <ndk/rtlfuncs.h>
11 
12 #include <sys/param.h>
13 
14 #include "tcpip.h"
15 
16 #define TAG_TEST 'tseT'
17 
18 #if BYTE_ORDER == LITTLE_ENDIAN
19 USHORT
20 htons(USHORT x)
21 {
22     return ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8);
23 }
24 #else
25 #define htons(x) (x)
26 #endif
27 
28 static
29 NTSTATUS
30 NTAPI
31 IrpCompletionRoutine(
32     _In_ PDEVICE_OBJECT    DeviceObject,
33     _In_ PIRP              Irp,
34     _In_ PVOID             Context)
35 {
36     UNREFERENCED_PARAMETER(DeviceObject);
37     UNREFERENCED_PARAMETER(Irp);
38 
39     KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
40 
41     return STATUS_MORE_PROCESSING_REQUIRED;
42 }
43 
44 static
45 VOID
46 TestTcpConnect(void)
47 {
48     PIRP Irp;
49     HANDLE AddressHandle, ConnectionHandle;
50     FILE_OBJECT* ConnectionFileObject;
51     DEVICE_OBJECT* DeviceObject;
52     UNICODE_STRING TcpDeviceName = RTL_CONSTANT_STRING(L"\\Device\\Tcp");
53     NTSTATUS Status;
54     PFILE_FULL_EA_INFORMATION FileInfo;
55     TA_IP_ADDRESS* IpAddress;
56     TA_IP_ADDRESS ConnectAddress, ReturnAddress;
57     OBJECT_ATTRIBUTES ObjectAttributes;
58     IO_STATUS_BLOCK StatusBlock;
59     ULONG FileInfoSize;
60     IN_ADDR InAddr;
61     LPCWSTR AddressTerminator;
62     CONNECTION_CONTEXT ConnectionContext = (CONNECTION_CONTEXT)(ULONG_PTR)0xC0CAC01AC0CAC01AULL;
63     KEVENT Event;
64     TDI_CONNECTION_INFORMATION RequestInfo, ReturnInfo;
65 
66     /* Create a TCP address file */
67     FileInfoSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[TDI_TRANSPORT_ADDRESS_LENGTH]) + 1 + sizeof(TA_IP_ADDRESS);
68     FileInfo = ExAllocatePoolWithTag(NonPagedPool,
69             FileInfoSize,
70             TAG_TEST);
71     ok(FileInfo != NULL, "FileInfo is NULL!\n");
72     RtlZeroMemory(FileInfo, FileInfoSize);
73 
74     FileInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
75     FileInfo->EaValueLength = sizeof(TA_IP_ADDRESS);
76     RtlCopyMemory(&FileInfo->EaName[0], TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);
77 
78     IpAddress = (PTA_IP_ADDRESS)(&FileInfo->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1]);
79     IpAddress->TAAddressCount = 1;
80     IpAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
81     IpAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
82     IpAddress->Address[0].Address[0].sin_port = htons(TEST_CONNECT_CLIENT_PORT);
83     Status = RtlIpv4StringToAddressW(L"127.0.0.1", TRUE, &AddressTerminator, &InAddr);
84     ok_eq_hex(Status, STATUS_SUCCESS);
85     IpAddress->Address[0].Address[0].in_addr = InAddr.S_un.S_addr;
86 
87     InitializeObjectAttributes(&ObjectAttributes,
88             &TcpDeviceName,
89             OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
90             NULL,
91             NULL);
92 
93     Status = ZwCreateFile(
94         &AddressHandle,
95         GENERIC_READ | GENERIC_WRITE,
96         &ObjectAttributes,
97         &StatusBlock,
98         0,
99         FILE_ATTRIBUTE_NORMAL,
100         FILE_SHARE_READ | FILE_SHARE_WRITE,
101         FILE_OPEN_IF,
102         0L,
103         FileInfo,
104         FileInfoSize);
105     ok_eq_hex(Status, STATUS_SUCCESS);
106 
107     ExFreePoolWithTag(FileInfo, TAG_TEST);
108 
109     /* Create a TCP connection file */
110     FileInfoSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[TDI_CONNECTION_CONTEXT_LENGTH]) + 1 + sizeof(CONNECTION_CONTEXT);
111     FileInfo = ExAllocatePoolWithTag(NonPagedPool,
112             FileInfoSize,
113             TAG_TEST);
114     ok(FileInfo != NULL, "FileInfo is NULL!\n");
115     RtlZeroMemory(FileInfo, FileInfoSize);
116 
117     FileInfo->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
118     FileInfo->EaValueLength = sizeof(CONNECTION_CONTEXT);
119     RtlCopyMemory(&FileInfo->EaName[0], TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH);
120     *((CONNECTION_CONTEXT*)&FileInfo->EaName[TDI_CONNECTION_CONTEXT_LENGTH + 1]) = ConnectionContext;
121 
122     Status = ZwCreateFile(
123         &ConnectionHandle,
124         GENERIC_READ | GENERIC_WRITE,
125         &ObjectAttributes,
126         &StatusBlock,
127         0,
128         FILE_ATTRIBUTE_NORMAL,
129         FILE_SHARE_READ | FILE_SHARE_WRITE,
130         FILE_OPEN_IF,
131         0L,
132         FileInfo,
133         FileInfoSize);
134     ok_eq_hex(Status, STATUS_SUCCESS);
135 
136     ExFreePoolWithTag(FileInfo, TAG_TEST);
137 
138     /* Get the file and device object for the upcoming IRPs */
139     Status = ObReferenceObjectByHandle(
140         ConnectionHandle,
141         GENERIC_READ,
142         *IoFileObjectType,
143         KernelMode,
144         (PVOID*)&ConnectionFileObject,
145         NULL);
146     ok_eq_hex(Status, STATUS_SUCCESS);
147     DeviceObject = IoGetRelatedDeviceObject(ConnectionFileObject);
148     ok(DeviceObject != NULL, "Device object is NULL!\n");
149 
150     /* Associate the connection file and the address */
151     KeInitializeEvent(&Event, NotificationEvent, FALSE);
152     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
153     ok(Irp != NULL, "IoAllocateIrp failed.\n");
154 
155     TdiBuildAssociateAddress(Irp, DeviceObject, ConnectionFileObject, NULL, NULL, AddressHandle);
156     IoSetCompletionRoutine(Irp, IrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
157 
158     Status = IoCallDriver(DeviceObject, Irp);
159     if (Status == STATUS_PENDING)
160     {
161         trace("Associate address IRP is pending.\n");
162         KeWaitForSingleObject(
163             &Event,
164             Executive,
165             KernelMode,
166             FALSE,
167             NULL);
168         Status = Irp->IoStatus.Status;
169     }
170     ok_eq_hex(Status, STATUS_SUCCESS);
171     IoFreeIrp(Irp);
172 
173 
174     KeClearEvent(&Event);
175 
176     /* Build the connect IRP. */
177     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
178     ok(Irp != NULL, "IoAllocateIrp failed.\n");
179 
180     /* Prepare the request */
181     RtlZeroMemory(&RequestInfo, sizeof(RequestInfo));
182     RtlZeroMemory(&ConnectAddress, sizeof(ConnectAddress));
183     RequestInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
184     RequestInfo.RemoteAddress = &ConnectAddress;
185     ConnectAddress.TAAddressCount = 1;
186     ConnectAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
187     ConnectAddress.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
188     ConnectAddress.Address[0].Address[0].sin_port = htons(TEST_CONNECT_SERVER_PORT);
189     Status = RtlIpv4StringToAddressW(L"127.0.0.1", TRUE, &AddressTerminator, &InAddr);
190     ConnectAddress.Address[0].Address[0].in_addr = InAddr.S_un.S_addr;
191 
192     /* See what we will get in exchange */
193     RtlZeroMemory(&ReturnInfo, sizeof(ReturnInfo));
194     RtlZeroMemory(&ReturnAddress, sizeof(ReturnAddress));
195     ReturnInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
196     ReturnInfo.RemoteAddress = &ReturnAddress;
197 
198     TdiBuildConnect(Irp,
199         DeviceObject,
200         ConnectionFileObject,
201         NULL,
202         NULL,
203         NULL,
204         &RequestInfo,
205         &ReturnInfo);
206     IoSetCompletionRoutine(Irp, IrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
207 
208     Status = IoCallDriver(DeviceObject, Irp);
209     if (Status == STATUS_PENDING)
210     {
211         trace("Connect IRP is pending.\n");
212         KeWaitForSingleObject(
213             &Event,
214             Executive,
215             KernelMode,
216             FALSE,
217             NULL);
218         Status = Irp->IoStatus.Status;
219         trace("Connect IRP completed.\n");
220     }
221     ok_eq_hex(Status, STATUS_SUCCESS);
222     IoFreeIrp(Irp);
223 
224     /* The IRP doesn't touch the return info */
225     ok_eq_long(ReturnInfo.RemoteAddressLength, sizeof(TA_IP_ADDRESS));
226     ok_eq_pointer(ReturnInfo.RemoteAddress, &ReturnAddress);
227     ok_eq_long(ReturnInfo.OptionsLength, 0);
228     ok_eq_pointer(ReturnInfo.Options, NULL);
229     ok_eq_long(ReturnInfo.UserDataLength, 0);
230     ok_eq_pointer(ReturnInfo.UserData, NULL);
231 
232     ok_eq_long(ReturnAddress.TAAddressCount, 0);
233     ok_eq_hex(ReturnAddress.Address[0].AddressType, 0);
234     ok_eq_hex(ReturnAddress.Address[0].AddressLength, 0);
235     ok_eq_hex(ReturnAddress.Address[0].Address[0].sin_port, 0);
236     ok_eq_hex(ReturnAddress.Address[0].Address[0].in_addr, 0);
237 
238     ObDereferenceObject(ConnectionFileObject);
239 
240     ZwClose(ConnectionHandle);
241     ZwClose(AddressHandle);
242 }
243 
244 static KSTART_ROUTINE RunTest;
245 static
246 VOID
247 NTAPI
248 RunTest(
249     _In_ PVOID Context)
250 {
251     UNREFERENCED_PARAMETER(Context);
252 
253     TestTcpConnect();
254 }
255 
256 KMT_MESSAGE_HANDLER TestConnect;
257 NTSTATUS
258 TestConnect(
259     _In_ PDEVICE_OBJECT DeviceObject,
260     _In_ ULONG ControlCode,
261     _In_opt_ PVOID Buffer,
262     _In_ SIZE_T InLength,
263     _Inout_ PSIZE_T OutLength
264 )
265 {
266     PKTHREAD Thread;
267 
268     Thread = KmtStartThread(RunTest, NULL);
269     KmtFinishThread(Thread, NULL);
270 
271     return STATUS_SUCCESS;
272 }
273