More work on winsock stack (ping is now working)
[reactos.git] / reactos / drivers / net / afd / afd / tdi.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Ancillary Function Driver
4 * FILE: afd/tdi.c
5 * PURPOSE: Transport Driver Interface functions
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/09-2000 Created
9 */
10 #include <afd.h>
11
12 #ifdef DBG
13 VOID DisplayBuffer(
14 PVOID Buffer,
15 ULONG Size)
16 {
17 ULONG i;
18 PCHAR p;
19
20 if ((DebugTraceLevel & MAX_TRACE) == 0)
21 return;
22
23 if (!Buffer) {
24 AFD_DbgPrint(MIN_TRACE, ("Cannot display null buffer.\n"));
25 return;
26 }
27
28 AFD_DbgPrint(MIN_TRACE, ("Displaying buffer at (0x%X) Size (%d).\n", Buffer, Size));
29
30 p = (PCHAR)Buffer;
31 for (i = 0; i < Size; i++) {
32 if (i % 16 == 0)
33 DbgPrint("\n");
34 DbgPrint("%02X ", (p[i]) & 0xFF);
35 }
36 DbgPrint("\n");
37 }
38 #endif /* DBG */
39
40
41 inline DWORD TdiAddressSizeFromName(
42 LPSOCKADDR Name)
43 /*
44 * FUNCTION: Returns the size of a TDI style address equivalent to a
45 * WinSock style name
46 * ARGUMENTS:
47 * Name = WinSock style name
48 * RETURNS:
49 * Size of TDI style address, 0 if Name is not valid
50 */
51 {
52 switch (Name->sa_family) {
53 case AF_INET:
54 return sizeof(TA_ADDRESS_IP);
55 /* FIXME: More to come */
56 }
57 AFD_DbgPrint(MIN_TRACE, ("Unknown address family (%d).\n", Name->sa_family));
58 return 0;
59 }
60
61
62 VOID TdiBuildAddressIPv4(
63 PTA_ADDRESS_IP Address,
64 LPSOCKADDR Name)
65 /*
66 * FUNCTION: Builds an IPv4 TDI style address
67 * ARGUMENTS:
68 * Address = Address of buffer to place TDI style IPv4 address
69 * Name = Pointer to WinSock style IPv4 name
70 */
71 {
72 Address->TAAddressCount = 1;
73 Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
74 Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
75 Address->Address[0].Address[0].sin_port = ((LPSOCKADDR_IN)Name)->sin_port;
76 Address->Address[0].Address[0].in_addr = ((LPSOCKADDR_IN)Name)->sin_addr.S_un.S_addr;
77 }
78
79
80 VOID TdiBuildAddress(
81 PTA_ADDRESS Address,
82 LPSOCKADDR Name)
83 /*
84 * FUNCTION: Builds a TDI style address
85 * ARGUMENTS:
86 * Address = Address of buffer to place TDI style address
87 * Name = Pointer to WinSock style name
88 */
89 {
90 switch (Name->sa_family) {
91 case AF_INET:
92 TdiBuildAddressIPv4((PTA_ADDRESS_IP)Address, Name);
93 break;
94 /* FIXME: More to come */
95 default:
96 AFD_DbgPrint(MIN_TRACE, ("Unknown address family (%d).\n", Name->sa_family));
97 }
98 }
99
100
101 VOID TdiBuildName(
102 LPSOCKADDR Name,
103 PTA_ADDRESS Address)
104 /*
105 * FUNCTION: Builds a WinSock style address
106 * ARGUMENTS:
107 * Name = Address of buffer to place WinSock style name
108 * Address = Pointer to TDI style address
109 */
110 {
111 switch (Address->AddressType) {
112 case TDI_ADDRESS_TYPE_IP:
113 Name->sa_family = AF_INET;
114 ((LPSOCKADDR_IN)Name)->sin_port =
115 ((PTDI_ADDRESS_IP)&Address->Address[0])->sin_port;
116 ((LPSOCKADDR_IN)Name)->sin_addr.S_un.S_addr =
117 ((PTDI_ADDRESS_IP)&Address->Address[0])->in_addr;
118 return;
119 /* FIXME: More to come */
120 }
121 AFD_DbgPrint(MIN_TRACE, ("Unknown TDI address type (%d).\n", Address->AddressType));
122 }
123
124
125 NTSTATUS TdiCall(
126 PIRP Irp,
127 PDEVICE_OBJECT DeviceObject,
128 PIO_STATUS_BLOCK IoStatusBlock,
129 BOOLEAN CanCancel,
130 PKEVENT StopEvent)
131 /*
132 * FUNCTION: Calls a transport driver device
133 * ARGUMENTS:
134 * Irp = Pointer to I/O Request Packet
135 * DeviceObject = Pointer to device object to call
136 * IoStatusBlock = Address of buffer with I/O status block
137 * CanCancel = TRUE if the IRP can be cancelled, FALSE if not
138 * StopEvent = If CanCancel is TRUE, a pointer to an event handle
139 * that, when signalled will cause the request to abort
140 * RETURNS:
141 * Status of operation
142 * NOTES:
143 * All requests are completed synchronously. A request can be cancelled
144 */
145 {
146 KEVENT Event;
147 PKEVENT Events[2];
148 NTSTATUS Status;
149 Events[0] = StopEvent;
150 Events[1] = &Event;
151
152 AFD_DbgPrint(MAX_TRACE, ("Called\n"));
153
154 KeInitializeEvent(&Event, NotificationEvent, FALSE);
155 Irp->UserEvent = &Event;
156 Irp->UserIosb = IoStatusBlock;
157 Status = IoCallDriver(DeviceObject, Irp);
158 if (Status == STATUS_PENDING) {
159 if (CanCancel) {
160 Status = KeWaitForMultipleObjects(2,
161 (PVOID)&Events,
162 WaitAny,
163 Executive,
164 KernelMode,
165 FALSE,
166 NULL,
167 NULL);
168
169 if (KeReadStateEvent(StopEvent) != 0) {
170 if (IoCancelIrp(Irp)) {
171 AFD_DbgPrint(MAX_TRACE, ("Cancelled IRP.\n"));
172 } else {
173 AFD_DbgPrint(MIN_TRACE, ("Could not cancel IRP.\n"));
174 }
175 return STATUS_CANCELLED;
176 }
177 } else
178 Status = KeWaitForSingleObject(&Event,
179 Executive,
180 KernelMode,
181 FALSE,
182 NULL);
183 }
184
185 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X) Iosb.Status (0x%X).\n", Status, IoStatusBlock->Status));
186
187 return IoStatusBlock->Status;
188 }
189
190
191 NTSTATUS TdiOpenDevice(
192 PUNICODE_STRING DeviceName,
193 ULONG EaLength,
194 PFILE_FULL_EA_INFORMATION EaInfo,
195 PHANDLE Handle,
196 PFILE_OBJECT *Object)
197 /*
198 * FUNCTION: Opens a device
199 * ARGUMENTS:
200 * DeviceName = Pointer to counted string with name of device
201 * EaLength = Length of EA information
202 * EaInfo = Pointer to buffer with EA information
203 * Handle = Address of buffer to place device handle
204 * Object = Address of buffer to place device object
205 * RETURNS:
206 * Status of operation
207 */
208 {
209 OBJECT_ATTRIBUTES Attr;
210 IO_STATUS_BLOCK Iosb;
211 NTSTATUS Status;
212
213 AFD_DbgPrint(MAX_TRACE, ("Called. DeviceName (%wZ)\n", DeviceName));
214
215 InitializeObjectAttributes(&Attr, /* Attribute buffer */
216 DeviceName, /* Device name */
217 OBJ_CASE_INSENSITIVE, /* Attributes */
218 NULL, /* Root directory */
219 NULL); /* Security descriptor */
220
221 Status = ZwCreateFile(Handle, /* Return file handle */
222 GENERIC_READ | GENERIC_WRITE, /* Desired access */
223 &Attr, /* Object attributes */
224 &Iosb, /* IO status */
225 0, /* Initial allocation size */
226 FILE_ATTRIBUTE_NORMAL, /* File attributes */
227 FILE_SHARE_READ | FILE_SHARE_WRITE, /* Share access */
228 FILE_OPEN_IF, /* Create disposition */
229 0, /* Create options */
230 EaInfo, /* EA buffer */
231 EaLength); /* EA length */
232 if (NT_SUCCESS(Status)) {
233 Status = ObReferenceObjectByHandle(*Handle, /* Handle to open file */
234 GENERIC_READ | GENERIC_WRITE, /* Access mode */
235 NULL, /* Object type */
236 KernelMode, /* Access mode */
237 (PVOID*)Object, /* Pointer to object */
238 NULL); /* Handle information */
239 if (!NT_SUCCESS(Status)) {
240 AFD_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status));
241 ZwClose(*Handle);
242 } else {
243 AFD_DbgPrint(MAX_TRACE, ("Got handle (0x%X) Object (0x%X)\n",
244 *Handle, *Object));
245 }
246 } else {
247 AFD_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status));
248 }
249 return Status;
250 }
251
252
253 NTSTATUS TdiCloseDevice(
254 HANDLE Handle,
255 PFILE_OBJECT FileObject)
256 {
257 AFD_DbgPrint(MAX_TRACE, ("Called. Handle (0x%X) FileObject (0x%X)\n",
258 Handle, FileObject));
259
260 if (Handle)
261 ZwClose(Handle);
262
263 if (FileObject)
264 ObDereferenceObject(FileObject);
265
266 return STATUS_SUCCESS;
267 }
268
269
270 NTSTATUS TdiOpenAddressFileIPv4(
271 PUNICODE_STRING DeviceName,
272 LPSOCKADDR Name,
273 PHANDLE AddressHandle,
274 PFILE_OBJECT *AddressObject)
275 /*
276 * FUNCTION: Opens an IPv4 address file object
277 * ARGUMENTS:
278 * DeviceName = Pointer to counted string with name of device
279 * Name = Pointer to socket name (IPv4 address family)
280 * AddressHandle = Address of buffer to place address file handle
281 * AddressObject = Address of buffer to place address file object
282 * RETURNS:
283 * Status of operation
284 */
285 {
286 PFILE_FULL_EA_INFORMATION EaInfo;
287 PTA_ADDRESS_IP Address;
288 NTSTATUS Status;
289 ULONG EaLength;
290
291 AFD_DbgPrint(MAX_TRACE, ("Called. DeviceName (%wZ) Name (0x%X)\n",
292 DeviceName, Name));
293
294 EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
295 TDI_TRANSPORT_ADDRESS_LENGTH +
296 sizeof(TA_ADDRESS_IP);
297 EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength);
298 if (!EaInfo)
299 return STATUS_INSUFFICIENT_RESOURCES;
300
301 RtlZeroMemory(EaInfo, EaLength);
302 EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
303 RtlCopyMemory(EaInfo->EaName,
304 TdiTransportAddress,
305 TDI_TRANSPORT_ADDRESS_LENGTH);
306 EaInfo->EaValueLength = sizeof(TA_ADDRESS_IP);
307 Address = (PTA_ADDRESS_IP)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH);
308 TdiBuildAddressIPv4(Address, Name);
309 Status = TdiOpenDevice(DeviceName,
310 EaLength,
311 EaInfo,
312 AddressHandle,
313 AddressObject);
314 ExFreePool(EaInfo);
315 return Status;
316 }
317
318
319 NTSTATUS TdiOpenAddressFile(
320 PUNICODE_STRING DeviceName,
321 LPSOCKADDR Name,
322 PHANDLE AddressHandle,
323 PFILE_OBJECT *AddressObject)
324 /*
325 * FUNCTION: Opens an address file object
326 * ARGUMENTS:
327 * DeviceName = Pointer to counted string with name of device
328 * Name = Pointer to socket name
329 * AddressHandle = Address of buffer to place address file handle
330 * AddressObject = Address of buffer to place address file object
331 * RETURNS:
332 * Status of operation
333 */
334 {
335 NTSTATUS Status;
336
337 switch (Name->sa_family) {
338 case AF_INET:
339 Status = TdiOpenAddressFileIPv4(
340 DeviceName,
341 Name,
342 AddressHandle,
343 AddressObject);
344 break;
345 default:
346 Status = STATUS_INVALID_PARAMETER;
347 }
348
349 return Status;
350 }
351
352
353 NTSTATUS TdiSetEventHandler(
354 PFILE_OBJECT FileObject,
355 LONG EventType,
356 PVOID Handler,
357 PVOID Context)
358 /*
359 * FUNCTION: Sets or resets an event handler
360 * ARGUMENTS:
361 * FileObject = Pointer to file object
362 * EventType = Event code
363 * Handler = Event handler to be called when the event occurs
364 * Context = Context input to handler when the event occurs
365 * RETURNS:
366 * Status of operation
367 * NOTES:
368 * Specify NULL for Handler to stop calling event handler
369 */
370 {
371 PDEVICE_OBJECT DeviceObject;
372 IO_STATUS_BLOCK Iosb;
373 NTSTATUS Status;
374 PIRP Irp;
375
376 AFD_DbgPrint(MAX_TRACE, ("Called\n"));
377
378 assert(FileObject);
379
380 DeviceObject = IoGetRelatedDeviceObject(FileObject);
381
382 Irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, /* Sub function */
383 DeviceObject, /* Device object */
384 FileObject, /* File object */
385 NULL, /* Event */
386 NULL); /* Status */
387 if (!Irp) {
388 AFD_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n"));
389 return STATUS_INSUFFICIENT_RESOURCES;
390 }
391
392 TdiBuildSetEventHandler(Irp,
393 DeviceObject,
394 FileObject,
395 NULL,
396 NULL,
397 EventType,
398 Handler,
399 Context);
400
401 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE, NULL);
402
403 return Status;
404 }
405
406
407 NTSTATUS TdiQueryDeviceControl(
408 PFILE_OBJECT FileObject,
409 ULONG IoControlCode,
410 PVOID InputBuffer,
411 ULONG InputBufferLength,
412 PVOID OutputBuffer,
413 ULONG OutputBufferLength,
414 PULONG Return)
415 /*
416 * FUNCTION: Queries a device for information
417 * ARGUMENTS:
418 * FileObject = Pointer to file object
419 * IoControlCode = I/O control code
420 * InputBuffer = Pointer to buffer with input data
421 * InputBufferLength = Length of InputBuffer
422 * OutputBuffer = Address of buffer to place output data
423 * OutputBufferLength = Length of OutputBuffer
424 * RETURNS:
425 * Status of operation
426 */
427 {
428 PDEVICE_OBJECT DeviceObject;
429 IO_STATUS_BLOCK Iosb;
430 NTSTATUS Status;
431 PIRP Irp;
432
433 DeviceObject = IoGetRelatedDeviceObject(FileObject);
434 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
435 DeviceObject,
436 InputBuffer,
437 InputBufferLength,
438 OutputBuffer,
439 OutputBufferLength,
440 FALSE,
441 NULL,
442 NULL);
443 if (!Irp) {
444 AFD_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed.\n"));
445 return STATUS_INSUFFICIENT_RESOURCES;
446 }
447
448 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE, NULL);
449 if (Return)
450 *Return = Iosb.Information;
451
452 return Status;
453 }
454
455
456 NTSTATUS TdiQueryInformationEx(
457 PFILE_OBJECT FileObject,
458 ULONG Entity,
459 ULONG Instance,
460 ULONG Class,
461 ULONG Type,
462 ULONG Id,
463 PVOID OutputBuffer,
464 PULONG OutputLength)
465 /*
466 * FUNCTION: Extended query for information
467 * ARGUMENTS:
468 * FileObject = Pointer to file object
469 * Entity = Entity
470 * Instance = Instance
471 * Class = Entity class
472 * Type = Entity type
473 * Id = Entity id
474 * OutputBuffer = Address of buffer to place data
475 * OutputLength = Address of buffer with length of OutputBuffer (updated)
476 * RETURNS:
477 * Status of operation
478 */
479 {
480 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
481
482 RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
483 QueryInfo.ID.toi_entity.tei_entity = Entity;
484 QueryInfo.ID.toi_entity.tei_instance = Instance;
485 QueryInfo.ID.toi_class = Class;
486 QueryInfo.ID.toi_type = Type;
487 QueryInfo.ID.toi_id = Id;
488
489 return TdiQueryDeviceControl(FileObject, /* Transport/connection object */
490 IOCTL_TCP_QUERY_INFORMATION_EX, /* Control code */
491 &QueryInfo, /* Input buffer */
492 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), /* Input buffer length */
493 OutputBuffer, /* Output buffer */
494 *OutputLength, /* Output buffer length */
495 OutputLength); /* Return information */
496 }
497
498
499 NTSTATUS TdiQueryAddress(
500 PFILE_OBJECT FileObject,
501 PULONG Address)
502 /*
503 * FUNCTION: Queries for a local IP address
504 * ARGUMENTS:
505 * FileObject = Pointer to file object
506 * Address = Address of buffer to place local address
507 * RETURNS:
508 * Status of operation
509 */
510 {
511 UINT i;
512 TDIEntityID *Entities;
513 ULONG EntityCount;
514 ULONG EntityType;
515 IPSNMP_INFO SnmpInfo;
516 PIPADDR_ENTRY IpAddress;
517 ULONG BufferSize;
518 NTSTATUS Status = STATUS_SUCCESS;
519
520 AFD_DbgPrint(MAX_TRACE, ("Called\n"));
521
522 BufferSize = sizeof(TDIEntityID) * 20;
523 Entities = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize);
524 if (!Entities) {
525 AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
526 return STATUS_INSUFFICIENT_RESOURCES;
527 }
528
529 /* Query device for supported entities */
530
531 Status = TdiQueryInformationEx(FileObject, /* File object */
532 GENERIC_ENTITY, /* Entity */
533 TL_INSTANCE, /* Instance */
534 INFO_CLASS_GENERIC, /* Entity class */
535 INFO_TYPE_PROVIDER, /* Entity type */
536 ENTITY_LIST_ID, /* Entity id */
537 Entities, /* Output buffer */
538 &BufferSize); /* Output buffer size */
539 if (!NT_SUCCESS(Status)) {
540 AFD_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status));
541 ExFreePool(Entities);
542 return Status;
543 }
544
545 /* Locate an IP entity */
546 EntityCount = BufferSize / sizeof(TDIEntityID);
547
548 AFD_DbgPrint(MAX_TRACE, ("EntityCount = %d\n", EntityCount));
549
550 for (i = 0; i < EntityCount; i++) {
551 if (Entities[i].tei_entity == CL_NL_ENTITY) {
552 /* Query device for entity type */
553
554 BufferSize = sizeof(EntityType);
555 Status = TdiQueryInformationEx(FileObject, /* File object */
556 CL_NL_ENTITY, /* Entity */
557 Entities[i].tei_instance, /* Instance */
558 INFO_CLASS_GENERIC, /* Entity class */
559 INFO_TYPE_PROVIDER, /* Entity type */
560 ENTITY_TYPE_ID, /* Entity id */
561 &EntityType, /* Output buffer */
562 &BufferSize); /* Output buffer size */
563 if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP)) {
564 AFD_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status));
565 break;
566 }
567
568 /* Query device for SNMP information */
569
570 BufferSize = sizeof(SnmpInfo);
571 Status = TdiQueryInformationEx(FileObject, /* File object */
572 CL_NL_ENTITY, /* Entity */
573 Entities[i].tei_instance, /* Instance */
574 INFO_CLASS_PROTOCOL, /* Entity class */
575 INFO_TYPE_PROVIDER, /* Entity type */
576 IP_MIB_STATS_ID, /* Entity id */
577 &SnmpInfo, /* Output buffer */
578 &BufferSize); /* Output buffer size */
579 if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0)) {
580 AFD_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status));
581 break;
582 }
583
584 /* Query device for all IP addresses */
585
586 if (SnmpInfo.NumAddr != 0) {
587 BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY);
588 IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize);
589 if (!IpAddress) {
590 AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
591 break;
592 }
593
594 Status = TdiQueryInformationEx(FileObject, /* File object */
595 CL_NL_ENTITY, /* Entity */
596 Entities[i].tei_instance, /* Instance */
597 INFO_CLASS_PROTOCOL, /* Entity class */
598 INFO_TYPE_PROVIDER, /* Entity type */
599 IP_MIB_ADDRTABLE_ENTRY_ID, /* Entity id */
600 IpAddress, /* Output buffer */
601 &BufferSize); /* Output buffer size */
602 if (!NT_SUCCESS(Status)) {
603 AFD_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status));
604 ExFreePool(IpAddress);
605 break;
606 }
607
608 if (SnmpInfo.NumAddr != 1) {
609 /* Skip loopback address */
610 *Address = DN2H(((PIPADDR_ENTRY)((ULONG)IpAddress + sizeof(IPADDR_ENTRY)))->Addr);
611 } else {
612 /* Select the first address returned */
613 *Address = DN2H(IpAddress->Addr);
614 }
615
616 ExFreePool(IpAddress);
617 } else {
618 Status = STATUS_UNSUCCESSFUL;
619 break;
620 }
621 }
622 }
623
624 ExFreePool(Entities);
625
626 AFD_DbgPrint(MAX_TRACE, ("Leaving\n"));
627
628 return Status;
629 }
630
631
632 NTSTATUS TdiSend(
633 PFILE_OBJECT TransportObject,
634 PVOID Buffer,
635 ULONG BufferSize)
636 /*
637 * FUNCTION: Sends a block of data
638 * ARGUMENTS:
639 * TransportObject = Pointer to transport object
640 * Buffer = Pointer to buffer with data to send
641 * BufferSize = Length of Buffer
642 * RETURNS:
643 * Status of operation
644 */
645 {
646 #if 0
647 PTDI_CONNECTION_INFORMATION ConnectInfo;
648 PDEVICE_OBJECT DeviceObject;
649 IO_STATUS_BLOCK Iosb;
650 DWORD TdiAddressSize;
651 PVOID BaseAddress;
652 NTSTATUS Status;
653 PIRP Irp;
654 PMDL Mdl;
655
656 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
657 if (!DeviceObject) {
658 AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
659 return STATUS_INVALID_PARAMETER;
660 }
661
662 TdiAddressSize = TdiAddressSizeFromName(Address);
663
664 ConnectInfo = (PTDI_CONNECTION_INFORMATION)
665 ExAllocatePool(NonPagedPool,
666 sizeof(TDI_CONNECTION_INFORMATION) +
667 TdiAddressSize);
668
669 if (!ConnectInfo) {
670 AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
671 return STATUS_INSUFFICIENT_RESOURCES;
672 }
673
674 RtlZeroMemory(ConnectInfo,
675 sizeof(TDI_CONNECTION_INFORMATION) +
676 TdiAddressSize);
677
678 ConnectInfo->RemoteAddressLength = TdiAddressSize;
679 ConnectInfo->RemoteAddress = (PVOID)
680 (ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));
681
682 TdiBuildAddress(ConnectInfo->RemoteAddress, Address);
683
684 Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, /* Sub function */
685 DeviceObject, /* Device object */
686 TransportObject, /* File object */
687 NULL, /* Event */
688 NULL); /* Return buffer */
689 if (!Irp) {
690 AFD_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n"));
691 ExFreePool(ConnectInfo);
692 return STATUS_INSUFFICIENT_RESOURCES;
693 }
694
695 DisplayBuffer(Request->Buffers->buf, Request->Buffers->len);
696
697
698 /* FIXME: There may be more than one buffer */
699 BufferSize = Request->Buffers->len;
700 Mdl = IoAllocateMdl(
701 Request->Buffers->buf, /* Virtual address of buffer */
702 Request->Buffers->len, /* Length of buffer */
703 FALSE, /* Not secondary */
704 FALSE, /* Don't charge quota */
705 NULL); /* Don't use IRP */
706 if (!Mdl) {
707 AFD_DbgPrint(MIN_TRACE, ("IoAllocateMdl() failed.\n"));
708 IoFreeIrp(Irp);
709 ExFreePool(ConnectInfo);
710 return STATUS_INSUFFICIENT_RESOURCES;
711 }
712
713 #ifdef _MSC_VER
714 try {
715 #endif
716 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
717 #ifdef _MSC_VER
718 } except(EXCEPTION_EXECUTE_HANDLER) {
719 AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
720 IoFreeMdl(Mdl);
721 IoFreeIrp(Irp);
722 ExFreePool(ConnectInfo);
723 return STATUS_UNSUCCESSFUL;
724 }
725 #endif
726
727 BaseAddress = MmMapLockedPages(Mdl, KernelMode);
728
729 AFD_DbgPrint(MAX_TRACE, ("Mapped user mode buffer at 0x%X.\n", BaseAddress));
730
731 TdiBuildSendDatagram(Irp, /* I/O Request Packet */
732 DeviceObject, /* Device object */
733 TransportObject, /* File object */
734 NULL, /* Completion routine */
735 NULL, /* Completion context */
736 Mdl, /* Descriptor for data buffer */
737 BufferSize, /* Size of data to send */
738 ConnectInfo); /* Connection information */
739
740 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE, NULL);
741
742 MmUnmapLockedPages(BaseAddress, Mdl);
743
744 MmUnlockPages(Mdl);
745
746 IoFreeMdl(Mdl);
747
748 ExFreePool(ConnectInfo);
749
750 return Status;
751 #endif
752 return STATUS_SUCCESS;
753 }
754
755
756 NTSTATUS TdiSendDatagram(
757 PFILE_OBJECT TransportObject,
758 LPSOCKADDR Address,
759 PMDL Mdl,
760 ULONG BufferSize)
761 /*
762 * FUNCTION: Sends a datagram
763 * ARGUMENTS:
764 * TransportObject = Pointer to transport object
765 * Address = Remote address to send data to
766 * Mdl = MDL of buffer to send
767 * BufferSize = Length of buffer
768 * RETURNS:
769 * Status of operation
770 */
771 {
772 PTDI_CONNECTION_INFORMATION ConnectInfo;
773 PDEVICE_OBJECT DeviceObject;
774 IO_STATUS_BLOCK Iosb;
775 DWORD TdiAddressSize;
776 NTSTATUS Status;
777 PIRP Irp;
778
779 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
780 if (!DeviceObject) {
781 AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
782 return STATUS_INVALID_PARAMETER;
783 }
784
785 TdiAddressSize = TdiAddressSizeFromName(Address);
786
787 ConnectInfo = (PTDI_CONNECTION_INFORMATION)
788 ExAllocatePool(NonPagedPool,
789 sizeof(TDI_CONNECTION_INFORMATION) +
790 TdiAddressSize);
791 if (!ConnectInfo)
792 return STATUS_INSUFFICIENT_RESOURCES;
793
794 RtlZeroMemory(ConnectInfo,
795 sizeof(TDI_CONNECTION_INFORMATION) +
796 TdiAddressSize);
797
798 ConnectInfo->RemoteAddressLength = TdiAddressSize;
799 ConnectInfo->RemoteAddress = (PVOID)
800 (ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));
801
802 TdiBuildAddress(ConnectInfo->RemoteAddress, Address);
803
804 Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, /* Sub function */
805 DeviceObject, /* Device object */
806 TransportObject, /* File object */
807 NULL, /* Event */
808 NULL); /* Return buffer */
809 if (!Irp) {
810 AFD_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n"));
811 ExFreePool(ConnectInfo);
812 return STATUS_INSUFFICIENT_RESOURCES;
813 }
814
815 #if 0
816 Mdl = IoAllocateMdl(Buffer, /* Virtual address of buffer */
817 BufferSize, /* Length of buffer */
818 FALSE, /* Not secondary */
819 FALSE, /* Don't charge quota */
820 NULL); /* Don't use IRP */
821 if (!Mdl) {
822 AFD_DbgPrint(MIN_TRACE, ("IoAllocateMdl() failed.\n"));
823 IoFreeIrp(Irp);
824 ExFreePool(ConnectInfo);
825 return STATUS_INSUFFICIENT_RESOURCES;
826 }
827 #ifdef _MSC_VER
828 try {
829 #endif
830 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
831 #ifdef _MSC_VER
832 } except(EXCEPTION_EXECUTE_HANDLER) {
833 AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
834 IoFreeIrp(Irp);
835 ExFreePool(ConnectInfo);
836 return STATUS_UNSUCCESSFUL;
837 }
838 #endif
839 #endif
840
841 TdiBuildSendDatagram(Irp, /* I/O Request Packet */
842 DeviceObject, /* Device object */
843 TransportObject, /* File object */
844 NULL, /* Completion routine */
845 NULL, /* Completion context */
846 Mdl, /* Descriptor for data buffer */
847 BufferSize, /* Size of data to send */
848 ConnectInfo); /* Connection information */
849
850 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE, NULL);
851
852 #if 0
853 MmUnlockPages(Mdl);
854
855 IoFreeMdl(Mdl);
856 #endif
857
858 ExFreePool(ConnectInfo);
859
860 return Status;
861 }
862
863
864 NTSTATUS TdiReceiveDatagram(
865 PFILE_OBJECT TransportObject,
866 LPSOCKADDR From,
867 LPSOCKADDR Address,
868 PUCHAR Buffer,
869 PULONG BufferSize)
870 /*
871 * FUNCTION: Receives a datagram
872 * ARGUMENTS:
873 * TransportObject = Pointer to transport object
874 * From = Receive filter (NULL if none)
875 * Address = Address of buffer to place remote address
876 * Buffer = Address of buffer to place received data
877 * BufferSize = Address of buffer with length of Buffer (updated)
878 * RETURNS:
879 * Status of operation
880 */
881 {
882 PTDI_CONNECTION_INFORMATION ReceiveInfo;
883 PTDI_CONNECTION_INFORMATION ReturnInfo;
884 PTA_ADDRESS_IP ReturnAddress;
885 PDEVICE_OBJECT DeviceObject;
886 IO_STATUS_BLOCK Iosb;
887 DWORD TdiAddressSize;
888 NTSTATUS Status;
889 PIRP Irp;
890 PMDL Mdl;
891
892 if (From != NULL) {
893 /* FIXME: Check that the socket type match the socket */
894 }
895
896 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
897 if (!DeviceObject) {
898 AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
899 return STATUS_INVALID_PARAMETER;
900 }
901
902 /* FIXME: Get from socket information */
903 TdiAddressSize = sizeof(TA_ADDRESS_IP);
904
905 ReceiveInfo = (PTDI_CONNECTION_INFORMATION)
906 ExAllocatePool(NonPagedPool,
907 sizeof(TDI_CONNECTION_INFORMATION) +
908 sizeof(TDI_CONNECTION_INFORMATION) +
909 2 * TdiAddressSize);
910 if (!ReceiveInfo) {
911 AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
912 return STATUS_INSUFFICIENT_RESOURCES;
913 }
914
915 RtlZeroMemory(ReceiveInfo,
916 sizeof(TDI_CONNECTION_INFORMATION) +
917 sizeof(TDI_CONNECTION_INFORMATION) +
918 2 * TdiAddressSize);
919
920 if (From != NULL) {
921 ReceiveInfo->RemoteAddressLength = TdiAddressSize;
922 ReceiveInfo->RemoteAddress = (PVOID)
923 (ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION));
924 /* Filter datagrams */
925 TdiBuildAddress(ReceiveInfo->RemoteAddress, From);
926 } else {
927 /* Receive from any address */
928 ReceiveInfo->RemoteAddressLength = 0;
929 ReceiveInfo->RemoteAddress = NULL;
930 }
931
932 ReturnInfo = (PTDI_CONNECTION_INFORMATION)
933 (ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION) + TdiAddressSize);
934 ReturnInfo->RemoteAddressLength = TdiAddressSize;
935 ReturnInfo->RemoteAddress = (PVOID)
936 (ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION));
937
938 Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, /* Sub function */
939 DeviceObject, /* Device object */
940 TransportObject, /* File object */
941 NULL, /* Event */
942 NULL); /* Return buffer */
943 if (!Irp) {
944 AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
945 ExFreePool(ReceiveInfo);
946 return STATUS_INSUFFICIENT_RESOURCES;
947 }
948
949 Mdl = IoAllocateMdl(Buffer, /* Virtual address */
950 *BufferSize, /* Length of buffer */
951 FALSE, /* Not secondary */
952 FALSE, /* Don't charge quota */
953 NULL); /* Don't use IRP */
954 if (!Mdl) {
955 AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
956 IoFreeIrp(Irp);
957 ExFreePool(ReceiveInfo);
958 return STATUS_INSUFFICIENT_RESOURCES;
959 }
960
961 #ifdef _MSC_VER
962 try {
963 #endif
964 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
965 #ifdef _MSC_VER
966 } except (EXCEPTION_EXECUTE_HANDLER) {
967 AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
968 IoFreeMdl(Mdl);
969 IoFreeIrp(Irp);
970 ExFreePool(ReceiveInfo);
971 return STATUS_INSUFFICIENT_RESOURCES;
972 }
973 #endif
974
975 TdiBuildReceiveDatagram(Irp, /* I/O Request Packet */
976 DeviceObject, /* Device object */
977 TransportObject, /* File object */
978 NULL, /* Completion routine */
979 NULL, /* Completion context */
980 Mdl, /* Data buffer */
981 *BufferSize, /* Size of data buffer */
982 ReceiveInfo, /* Connection information */
983 ReturnInfo, /* Connection information */
984 TDI_RECEIVE_NORMAL); /* Flags */
985 Status = TdiCall(Irp, DeviceObject, &Iosb, TRUE, NULL);
986 if (NT_SUCCESS(Status)) {
987 *BufferSize = Iosb.Information;
988 TdiBuildName(Address, ReturnInfo->RemoteAddress);
989 }
990
991 MmUnlockPages(Mdl);
992
993 IoFreeMdl(Mdl);
994
995 ExFreePool(ReceiveInfo);
996
997 return Status;
998 }
999
1000 /* EOF */