Merge the following revisions from kernel-fun branch:
[reactos.git] / rostests / kmtests / tcpip / connect.c
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)0xC0CAC01A;
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, "");
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, "");
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 }