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