1 /*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Utility function definitions for calling AFD
5 * COPYRIGHT: Copyright 2015-2018 Thomas Faber (thomas.faber@reactos.org)
6 * Copyright 2019 Pierre Schweitzer (pierre@reactos.org)
7 */
8
9 #include "precomp.h"
10
11 #define DD_UDP_DEVICE_NAME L"\\Device\\Udp"
12
13 typedef struct _AFD_CREATE_PACKET_NT6 {
14 DWORD EndpointFlags;
15 DWORD GroupID;
16 DWORD AddressFamily;
17 DWORD SocketType;
18 DWORD Protocol;
19 DWORD SizeOfTransportName;
20 WCHAR TransportName[1];
21 } AFD_CREATE_PACKET_NT6, *PAFD_CREATE_PACKET_NT6;
22
23 NTSTATUS
AfdCreateSocket(_Out_ PHANDLE SocketHandle,_In_ int AddressFamily,_In_ int SocketType,_In_ int Protocol)24 AfdCreateSocket(
25 _Out_ PHANDLE SocketHandle,
26 _In_ int AddressFamily,
27 _In_ int SocketType,
28 _In_ int Protocol)
29 {
30 NTSTATUS Status;
31 OBJECT_ATTRIBUTES ObjectAttributes;
32 IO_STATUS_BLOCK IoStatus;
33 PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
34 ULONG EaLength;
35 PAFD_CREATE_PACKET AfdPacket;
36 PAFD_CREATE_PACKET_NT6 AfdPacket6;
37 ULONG SizeOfPacket;
38 ANSI_STRING EaName = RTL_CONSTANT_STRING(AfdCommand);
39 UNICODE_STRING TcpTransportName = RTL_CONSTANT_STRING(DD_TCP_DEVICE_NAME);
40 UNICODE_STRING UdpTransportName = RTL_CONSTANT_STRING(DD_UDP_DEVICE_NAME);
41 UNICODE_STRING TransportName = SocketType == SOCK_STREAM ? TcpTransportName : UdpTransportName;
42 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Afd\\Endpoint");
43
44 *SocketHandle = NULL;
45
46 if (LOBYTE(LOWORD(GetVersion())) >= 6)
47 {
48 SizeOfPacket = FIELD_OFFSET(AFD_CREATE_PACKET_NT6, TransportName) + TransportName.Length + sizeof(UNICODE_NULL);
49 }
50 else
51 {
52 SizeOfPacket = FIELD_OFFSET(AFD_CREATE_PACKET, TransportName) + TransportName.Length + sizeof(UNICODE_NULL);
53 }
54 EaLength = SizeOfPacket + FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + EaName.Length + sizeof(ANSI_NULL);
55
56 /* Set up EA Buffer */
57 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EaLength);
58 if (!EaBuffer)
59 {
60 return STATUS_INSUFFICIENT_RESOURCES;
61 }
62
63 EaBuffer->NextEntryOffset = 0;
64 EaBuffer->Flags = 0;
65 EaBuffer->EaNameLength = EaName.Length;
66 RtlCopyMemory(EaBuffer->EaName,
67 EaName.Buffer,
68 EaName.Length + sizeof(ANSI_NULL));
69 EaBuffer->EaValueLength = SizeOfPacket;
70
71 if (LOBYTE(LOWORD(GetVersion())) >= 6)
72 {
73 AfdPacket6 = (PAFD_CREATE_PACKET_NT6)(EaBuffer->EaName + EaBuffer->EaNameLength + sizeof(ANSI_NULL));
74 AfdPacket6->GroupID = 0;
75 if (SocketType == SOCK_DGRAM)
76 {
77 AfdPacket6->EndpointFlags = AFD_ENDPOINT_CONNECTIONLESS;
78 }
79 else if (SocketType == SOCK_STREAM)
80 {
81 AfdPacket6->EndpointFlags = AFD_ENDPOINT_MESSAGE_ORIENTED;
82 }
83 AfdPacket6->AddressFamily = AddressFamily;
84 AfdPacket6->SocketType = SocketType;
85 AfdPacket6->Protocol = Protocol;
86 AfdPacket6->SizeOfTransportName = TransportName.Length;
87 RtlCopyMemory(AfdPacket6->TransportName,
88 TransportName.Buffer,
89 TransportName.Length + sizeof(UNICODE_NULL));
90 }
91 else
92 {
93 AfdPacket = (PAFD_CREATE_PACKET)(EaBuffer->EaName + EaBuffer->EaNameLength + sizeof(ANSI_NULL));
94 AfdPacket->GroupID = 0;
95 if (SocketType == SOCK_DGRAM)
96 {
97 AfdPacket->EndpointFlags = AFD_ENDPOINT_CONNECTIONLESS;
98 }
99 else if (SocketType == SOCK_STREAM)
100 {
101 AfdPacket->EndpointFlags = AFD_ENDPOINT_MESSAGE_ORIENTED;
102 }
103 AfdPacket->SizeOfTransportName = TransportName.Length;
104 RtlCopyMemory(AfdPacket->TransportName,
105 TransportName.Buffer,
106 TransportName.Length + sizeof(UNICODE_NULL));
107 }
108
109 InitializeObjectAttributes(&ObjectAttributes,
110 &DeviceName,
111 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
112 0,
113 0);
114
115 Status = NtCreateFile(SocketHandle,
116 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
117 &ObjectAttributes,
118 &IoStatus,
119 NULL,
120 0,
121 FILE_SHARE_READ | FILE_SHARE_WRITE,
122 FILE_OPEN_IF,
123 0,
124 EaBuffer,
125 EaLength);
126
127 RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
128
129 return Status;
130 }
131
132
133 NTSTATUS
AfdBind(_In_ HANDLE SocketHandle,_In_ const struct sockaddr * Address,_In_ ULONG AddressLength)134 AfdBind(
135 _In_ HANDLE SocketHandle,
136 _In_ const struct sockaddr *Address,
137 _In_ ULONG AddressLength)
138 {
139 NTSTATUS Status;
140 IO_STATUS_BLOCK IoStatus;
141 PAFD_BIND_DATA BindInfo;
142 ULONG BindInfoLength;
143 HANDLE Event;
144
145 Status = NtCreateEvent(&Event,
146 EVENT_ALL_ACCESS,
147 NULL,
148 NotificationEvent,
149 FALSE);
150 if (!NT_SUCCESS(Status))
151 {
152 return Status;
153 }
154
155 BindInfoLength = FIELD_OFFSET(AFD_BIND_DATA, Address.Address[0].Address) +
156 AddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
157 BindInfo = RtlAllocateHeap(RtlGetProcessHeap(),
158 0,
159 BindInfoLength);
160 if (!BindInfo)
161 {
162 NtClose(Event);
163 return STATUS_INSUFFICIENT_RESOURCES;
164 }
165
166 BindInfo->ShareType = AFD_SHARE_UNIQUE;
167 BindInfo->Address.TAAddressCount = 1;
168 BindInfo->Address.Address[0].AddressType = Address->sa_family;
169 BindInfo->Address.Address[0].AddressLength = AddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
170 RtlCopyMemory(&BindInfo->Address.Address[0].Address,
171 Address->sa_data,
172 BindInfo->Address.Address[0].AddressLength);
173
174 Status = NtDeviceIoControlFile(SocketHandle,
175 Event,
176 NULL,
177 NULL,
178 &IoStatus,
179 IOCTL_AFD_BIND,
180 BindInfo,
181 BindInfoLength,
182 BindInfo,
183 BindInfoLength);
184 if (Status == STATUS_PENDING)
185 {
186 NtWaitForSingleObject(Event, FALSE, NULL);
187 Status = IoStatus.Status;
188 }
189
190 RtlFreeHeap(RtlGetProcessHeap(), 0, BindInfo);
191 NtClose(Event);
192
193 return Status;
194 }
195
196 NTSTATUS
AfdConnect(_In_ HANDLE SocketHandle,_In_ const struct sockaddr * Address,_In_ ULONG AddressLength)197 AfdConnect(
198 _In_ HANDLE SocketHandle,
199 _In_ const struct sockaddr *Address,
200 _In_ ULONG AddressLength)
201 {
202 NTSTATUS Status;
203 IO_STATUS_BLOCK IoStatus;
204 PAFD_CONNECT_INFO ConnectInfo;
205 ULONG ConnectInfoLength;
206 HANDLE Event;
207
208 Status = NtCreateEvent(&Event,
209 EVENT_ALL_ACCESS,
210 NULL,
211 NotificationEvent,
212 FALSE);
213 if (!NT_SUCCESS(Status))
214 {
215 return Status;
216 }
217
218 ASSERT(FIELD_OFFSET(AFD_CONNECT_INFO, RemoteAddress.Address[0].Address) == 20);
219 ConnectInfoLength = FIELD_OFFSET(AFD_CONNECT_INFO, RemoteAddress.Address[0].Address) +
220 AddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
221 ConnectInfo = RtlAllocateHeap(RtlGetProcessHeap(),
222 0,
223 ConnectInfoLength);
224 if (!ConnectInfo)
225 {
226 NtClose(Event);
227 return STATUS_INSUFFICIENT_RESOURCES;
228 }
229
230
231 ConnectInfo->UseSAN = FALSE;
232 ConnectInfo->Root = 0;
233 ConnectInfo->Unknown = 0;
234 ConnectInfo->RemoteAddress.TAAddressCount = 1;
235 ConnectInfo->RemoteAddress.Address[0].AddressType = Address->sa_family;
236 ConnectInfo->RemoteAddress.Address[0].AddressLength = AddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
237 RtlCopyMemory(&ConnectInfo->RemoteAddress.Address[0].Address,
238 Address->sa_data,
239 ConnectInfo->RemoteAddress.Address[0].AddressLength);
240
241 Status = NtDeviceIoControlFile(SocketHandle,
242 Event,
243 NULL,
244 NULL,
245 &IoStatus,
246 IOCTL_AFD_CONNECT,
247 ConnectInfo,
248 ConnectInfoLength,
249 NULL,
250 0);
251 if (Status == STATUS_PENDING)
252 {
253 NtWaitForSingleObject(Event, FALSE, NULL);
254 Status = IoStatus.Status;
255 }
256
257 RtlFreeHeap(RtlGetProcessHeap(), 0, ConnectInfo);
258 NtClose(Event);
259
260 return Status;
261 }
262
263 NTSTATUS
AfdSend(_In_ HANDLE SocketHandle,_In_ const void * Buffer,_In_ ULONG BufferLength)264 AfdSend(
265 _In_ HANDLE SocketHandle,
266 _In_ const void *Buffer,
267 _In_ ULONG BufferLength)
268 {
269 NTSTATUS Status;
270 IO_STATUS_BLOCK IoStatus;
271 AFD_SEND_INFO SendInfo;
272 HANDLE Event;
273 AFD_WSABUF AfdBuffer;
274
275 Status = NtCreateEvent(&Event,
276 EVENT_ALL_ACCESS,
277 NULL,
278 NotificationEvent,
279 FALSE);
280 if (!NT_SUCCESS(Status))
281 {
282 return Status;
283 }
284
285 AfdBuffer.buf = (PVOID)Buffer;
286 AfdBuffer.len = BufferLength;
287 SendInfo.BufferArray = &AfdBuffer;
288 SendInfo.BufferCount = 1;
289 SendInfo.TdiFlags = 0;
290 SendInfo.AfdFlags = 0;
291
292 Status = NtDeviceIoControlFile(SocketHandle,
293 Event,
294 NULL,
295 NULL,
296 &IoStatus,
297 IOCTL_AFD_SEND,
298 &SendInfo,
299 sizeof(SendInfo),
300 NULL,
301 0);
302 if (Status == STATUS_PENDING)
303 {
304 NtWaitForSingleObject(Event, FALSE, NULL);
305 Status = IoStatus.Status;
306 }
307
308 NtClose(Event);
309
310 return Status;
311 }
312
313 NTSTATUS
AfdSendTo(_In_ HANDLE SocketHandle,_In_ const void * Buffer,_In_ ULONG BufferLength,_In_ const struct sockaddr * Address,_In_ ULONG AddressLength)314 AfdSendTo(
315 _In_ HANDLE SocketHandle,
316 _In_ const void *Buffer,
317 _In_ ULONG BufferLength,
318 _In_ const struct sockaddr *Address,
319 _In_ ULONG AddressLength)
320 {
321 NTSTATUS Status;
322 IO_STATUS_BLOCK IoStatus;
323 AFD_SEND_INFO_UDP SendInfo;
324 HANDLE Event;
325 AFD_WSABUF AfdBuffer;
326 PTRANSPORT_ADDRESS TransportAddress;
327 ULONG TransportAddressLength;
328
329 Status = NtCreateEvent(&Event,
330 EVENT_ALL_ACCESS,
331 NULL,
332 NotificationEvent,
333 FALSE);
334 if (!NT_SUCCESS(Status))
335 {
336 return Status;
337 }
338
339 TransportAddressLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address[0].Address) +
340 AddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
341 TransportAddress = RtlAllocateHeap(RtlGetProcessHeap(),
342 0,
343 TransportAddressLength);
344 if (!TransportAddress)
345 {
346 NtClose(Event);
347 return STATUS_INSUFFICIENT_RESOURCES;
348 }
349 TransportAddress->TAAddressCount = 1;
350 TransportAddress->Address[0].AddressType = Address->sa_family;
351 TransportAddress->Address[0].AddressLength = AddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
352 RtlCopyMemory(&TransportAddress->Address[0].Address,
353 Address->sa_data,
354 TransportAddress->Address[0].AddressLength);
355
356 AfdBuffer.buf = (PVOID)Buffer;
357 AfdBuffer.len = BufferLength;
358 RtlZeroMemory(&SendInfo, sizeof(SendInfo));
359 SendInfo.BufferArray = &AfdBuffer;
360 SendInfo.BufferCount = 1;
361 SendInfo.AfdFlags = 0;
362 SendInfo.TdiConnection.RemoteAddress = TransportAddress;
363 SendInfo.TdiConnection.RemoteAddressLength = TransportAddressLength;
364
365 Status = NtDeviceIoControlFile(SocketHandle,
366 Event,
367 NULL,
368 NULL,
369 &IoStatus,
370 IOCTL_AFD_SEND_DATAGRAM,
371 &SendInfo,
372 sizeof(SendInfo),
373 NULL,
374 0);
375 if (Status == STATUS_PENDING)
376 {
377 NtWaitForSingleObject(Event, FALSE, NULL);
378 Status = IoStatus.Status;
379 }
380
381 RtlFreeHeap(RtlGetProcessHeap(), 0, TransportAddress);
382 NtClose(Event);
383
384 return Status;
385 }
386
387 NTSTATUS
AfdSetInformation(_In_ HANDLE SocketHandle,_In_ ULONG InformationClass,_In_opt_ PBOOLEAN Boolean,_In_opt_ PULONG Ulong,_In_opt_ PLARGE_INTEGER LargeInteger)388 AfdSetInformation(
389 _In_ HANDLE SocketHandle,
390 _In_ ULONG InformationClass,
391 _In_opt_ PBOOLEAN Boolean,
392 _In_opt_ PULONG Ulong,
393 _In_opt_ PLARGE_INTEGER LargeInteger)
394 {
395 NTSTATUS Status;
396 IO_STATUS_BLOCK IoStatus;
397 AFD_INFO InfoData;
398 HANDLE Event;
399
400 Status = NtCreateEvent(&Event,
401 EVENT_ALL_ACCESS,
402 NULL,
403 NotificationEvent,
404 FALSE);
405 if (!NT_SUCCESS(Status))
406 {
407 return Status;
408 }
409
410 InfoData.InformationClass = InformationClass;
411
412 if (Ulong != NULL)
413 {
414 InfoData.Information.Ulong = *Ulong;
415 }
416 if (LargeInteger != NULL)
417 {
418 InfoData.Information.LargeInteger = *LargeInteger;
419 }
420 if (Boolean != NULL)
421 {
422 InfoData.Information.Boolean = *Boolean;
423 }
424
425 Status = NtDeviceIoControlFile(SocketHandle,
426 Event,
427 NULL,
428 NULL,
429 &IoStatus,
430 IOCTL_AFD_SET_INFO,
431 &InfoData,
432 sizeof(InfoData),
433 NULL,
434 0);
435 if (Status == STATUS_PENDING)
436 {
437 NtWaitForSingleObject(Event, FALSE, NULL);
438 Status = IoStatus.Status;
439 }
440
441 NtClose(Event);
442
443 return Status;
444 }
445
446 NTSTATUS
AfdGetInformation(_In_ HANDLE SocketHandle,_In_ ULONG InformationClass,_In_opt_ PBOOLEAN Boolean,_In_opt_ PULONG Ulong,_In_opt_ PLARGE_INTEGER LargeInteger)447 AfdGetInformation(
448 _In_ HANDLE SocketHandle,
449 _In_ ULONG InformationClass,
450 _In_opt_ PBOOLEAN Boolean,
451 _In_opt_ PULONG Ulong,
452 _In_opt_ PLARGE_INTEGER LargeInteger)
453 {
454 NTSTATUS Status;
455 IO_STATUS_BLOCK IoStatus;
456 AFD_INFO InfoData;
457 HANDLE Event;
458
459 Status = NtCreateEvent(&Event,
460 EVENT_ALL_ACCESS,
461 NULL,
462 NotificationEvent,
463 FALSE);
464 if (!NT_SUCCESS(Status))
465 {
466 return Status;
467 }
468
469 InfoData.InformationClass = InformationClass;
470
471 Status = NtDeviceIoControlFile(SocketHandle,
472 Event,
473 NULL,
474 NULL,
475 &IoStatus,
476 IOCTL_AFD_GET_INFO,
477 &InfoData,
478 sizeof(InfoData),
479 &InfoData,
480 sizeof(InfoData));
481 if (Status == STATUS_PENDING)
482 {
483 NtWaitForSingleObject(Event, FALSE, NULL);
484 Status = IoStatus.Status;
485 }
486
487 NtClose(Event);
488
489 if (Status != STATUS_SUCCESS)
490 {
491 return Status;
492 }
493
494 if (Ulong != NULL)
495 {
496 *Ulong = InfoData.Information.Ulong;
497 }
498 if (LargeInteger != NULL)
499 {
500 *LargeInteger = InfoData.Information.LargeInteger;
501 }
502 if (Boolean != NULL)
503 {
504 *Boolean = InfoData.Information.Boolean;
505 }
506
507 return Status;
508 }
509