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         trace("Associate address IRP completed.\n");
170     }
171     ok_eq_hex(Status, STATUS_SUCCESS);
172     IoFreeIrp(Irp);
173 
174 
175     KeClearEvent(&Event);
176 
177     /* Build the connect IRP. */
178     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
179     ok(Irp != NULL, "IoAllocateIrp failed.\n");
180 
181     /* Prepare the request */
182     RtlZeroMemory(&RequestInfo, sizeof(RequestInfo));
183     RtlZeroMemory(&ConnectAddress, sizeof(ConnectAddress));
184     RequestInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
185     RequestInfo.RemoteAddress = &ConnectAddress;
186     ConnectAddress.TAAddressCount = 1;
187     ConnectAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
188     ConnectAddress.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
189     ConnectAddress.Address[0].Address[0].sin_port = htons(TEST_CONNECT_SERVER_PORT);
190     Status = RtlIpv4StringToAddressW(L"127.0.0.1", TRUE, &AddressTerminator, &InAddr);
191     ConnectAddress.Address[0].Address[0].in_addr = InAddr.S_un.S_addr;
192 
193     /* See what we will get in exchange */
194     RtlZeroMemory(&ReturnInfo, sizeof(ReturnInfo));
195     RtlZeroMemory(&ReturnAddress, sizeof(ReturnAddress));
196     ReturnInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
197     ReturnInfo.RemoteAddress = &ReturnAddress;
198 
199     TdiBuildConnect(Irp,
200         DeviceObject,
201         ConnectionFileObject,
202         NULL,
203         NULL,
204         NULL,
205         &RequestInfo,
206         &ReturnInfo);
207     IoSetCompletionRoutine(Irp, IrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
208 
209     Status = IoCallDriver(DeviceObject, Irp);
210     if (Status == STATUS_PENDING)
211     {
212         trace("Connect IRP is pending.\n");
213         KeWaitForSingleObject(
214             &Event,
215             Executive,
216             KernelMode,
217             FALSE,
218             NULL);
219         Status = Irp->IoStatus.Status;
220         trace("Connect IRP completed.\n");
221     }
222     ok_eq_hex(Status, STATUS_SUCCESS);
223     IoFreeIrp(Irp);
224 
225     /* The IRP doesn't touch the return info */
226     ok_eq_long(ReturnInfo.RemoteAddressLength, sizeof(TA_IP_ADDRESS));
227     ok_eq_pointer(ReturnInfo.RemoteAddress, &ReturnAddress);
228     ok_eq_long(ReturnInfo.OptionsLength, 0);
229     ok_eq_pointer(ReturnInfo.Options, NULL);
230     ok_eq_long(ReturnInfo.UserDataLength, 0);
231     ok_eq_pointer(ReturnInfo.UserData, NULL);
232 
233     ok_eq_long(ReturnAddress.TAAddressCount, 1);
234     ok_eq_hex(ReturnAddress.Address[0].AddressType, TDI_ADDRESS_TYPE_IP);
235     ok_eq_hex(ReturnAddress.Address[0].AddressLength, TDI_ADDRESS_LENGTH_IP);
236     ok_eq_hex(ReturnAddress.Address[0].Address[0].sin_port, htons(TEST_CONNECT_SERVER_PORT));
237     ok_eq_hex(ReturnAddress.Address[0].Address[0].in_addr, InAddr.S_un.S_addr);
238 
239     ObDereferenceObject(ConnectionFileObject);
240 
241     ZwClose(ConnectionHandle);
242     ZwClose(AddressHandle);
243 }
244 
245 static KSTART_ROUTINE RunTest;
246 static
247 VOID
248 NTAPI
249 RunTest(
250     _In_ PVOID Context)
251 {
252     UNREFERENCED_PARAMETER(Context);
253 
254     TestTcpConnect();
255 }
256 
257 KMT_MESSAGE_HANDLER TestConnect;
258 NTSTATUS
259 TestConnect(
260     _In_ PDEVICE_OBJECT DeviceObject,
261     _In_ ULONG ControlCode,
262     _In_opt_ PVOID Buffer,
263     _In_ SIZE_T InLength,
264     _Inout_ PSIZE_T OutLength
265 )
266 {
267     PKTHREAD Thread;
268 
269     Thread = KmtStartThread(RunTest, NULL);
270     KmtFinishThread(Thread, NULL);
271 
272     return STATUS_SUCCESS;
273 }
274