xref: /reactos/drivers/network/afd/afd/tdi.c (revision b8309397)
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 
11 #include <afd.h>
12 
13 #include <tdikrnl.h>
14 #include <tdiinfo.h>
15 
16 #if DBG
17 #if 0
18 static VOID DisplayBuffer(
19     PVOID Buffer,
20     ULONG Size)
21 {
22     ULONG i;
23     PCHAR p;
24 
25     if ((DebugTraceLevel & MAX_TRACE) == 0)
26         return;
27 
28     if (!Buffer) {
29         AFD_DbgPrint(MIN_TRACE, ("Cannot display null buffer.\n"));
30         return;
31     }
32 
33     AFD_DbgPrint(MID_TRACE, ("Displaying buffer at (0x%X)  Size (%d).\n", Buffer, Size));
34 
35     p = (PCHAR)Buffer;
36     for (i = 0; i < Size; i++) {
37         if (i % 16 == 0)
38             DbgPrint("\n");
39         DbgPrint("%02X ", (p[i]) & 0xFF);
40     }
41     DbgPrint("\n");
42 }
43 #endif
44 #endif /* DBG */
45 
TdiCall(PIRP Irp,PDEVICE_OBJECT DeviceObject,PKEVENT Event,PIO_STATUS_BLOCK Iosb)46 static NTSTATUS TdiCall(
47     PIRP Irp,
48     PDEVICE_OBJECT DeviceObject,
49     PKEVENT Event,
50     PIO_STATUS_BLOCK Iosb)
51 /*
52  * FUNCTION: Calls a transport driver device
53  * ARGUMENTS:
54  *     Irp           = Pointer to I/O Request Packet
55  *     DeviceObject  = Pointer to device object to call
56  *     Event         = An optional pointer to an event handle that will be
57  *                     waited upon
58  *     Iosb          = Pointer to an IO status block
59  * RETURNS:
60  *     Status of operation
61  */
62 {
63     NTSTATUS Status;
64 
65     AFD_DbgPrint(MID_TRACE, ("Called\n"));
66 
67     AFD_DbgPrint(MID_TRACE, ("Irp->UserEvent = %p\n", Irp->UserEvent));
68 
69     Status = IoCallDriver(DeviceObject, Irp);
70     AFD_DbgPrint(MID_TRACE, ("IoCallDriver: %08x\n", Status));
71 
72     if ((Status == STATUS_PENDING) && (Event != NULL)) {
73         AFD_DbgPrint(MAX_TRACE, ("Waiting on transport.\n"));
74         KeWaitForSingleObject(Event,
75                               Executive,
76                               KernelMode,
77                               FALSE,
78                               NULL);
79         Status = Iosb->Status;
80     }
81 
82     AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
83 
84     return Status;
85 }
86 
87 
TdiOpenDevice(PUNICODE_STRING DeviceName,ULONG EaLength,PFILE_FULL_EA_INFORMATION EaInfo,ULONG ShareType,PHANDLE Handle,PFILE_OBJECT * Object)88 static NTSTATUS TdiOpenDevice(
89     PUNICODE_STRING DeviceName,
90     ULONG EaLength,
91     PFILE_FULL_EA_INFORMATION EaInfo,
92     ULONG ShareType,
93     PHANDLE Handle,
94     PFILE_OBJECT *Object)
95 /*
96  * FUNCTION: Opens a device
97  * ARGUMENTS:
98  *     DeviceName = Pointer to counted string with name of device
99  *     EaLength   = Length of EA information
100  *     EaInfo     = Pointer to buffer with EA information
101  *     Handle     = Address of buffer to place device handle
102  *     Object     = Address of buffer to place device object
103  * RETURNS:
104  *     Status of operation
105  */
106 {
107     OBJECT_ATTRIBUTES Attr;
108     IO_STATUS_BLOCK Iosb;
109     NTSTATUS Status;
110     ULONG ShareAccess;
111 
112     AFD_DbgPrint(MAX_TRACE, ("Called. DeviceName (%wZ, %u)\n", DeviceName, ShareType));
113 
114     /* Determine the share access */
115     if (ShareType != AFD_SHARE_REUSE)
116     {
117         /* Exclusive access */
118         ShareAccess = 0;
119     }
120     else
121     {
122         /* Shared access */
123         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
124     }
125 
126     InitializeObjectAttributes(&Attr,                   /* Attribute buffer */
127                                DeviceName,              /* Device name */
128                                OBJ_CASE_INSENSITIVE |   /* Attributes */
129                                OBJ_KERNEL_HANDLE,
130                                NULL,                    /* Root directory */
131                                NULL);                   /* Security descriptor */
132 
133     Status = ZwCreateFile(Handle,                               /* Return file handle */
134                           GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,         /* Desired access */
135                           &Attr,                                /* Object attributes */
136                           &Iosb,                                /* IO status */
137                           0,                                    /* Initial allocation size */
138                           FILE_ATTRIBUTE_NORMAL,                /* File attributes */
139                           ShareAccess,                          /* Share access */
140                           FILE_OPEN_IF,                         /* Create disposition */
141                           0,                                    /* Create options */
142                           EaInfo,                               /* EA buffer */
143                           EaLength);                            /* EA length */
144     if (NT_SUCCESS(Status)) {
145         Status = ObReferenceObjectByHandle(*Handle,                       /* Handle to open file */
146                                            GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,  /* Access mode */
147                                            *IoFileObjectType,              /* Object type */
148                                            KernelMode,                    /* Access mode */
149                                            (PVOID*)Object,                /* Pointer to object */
150                                            NULL);                         /* Handle information */
151         if (!NT_SUCCESS(Status)) {
152             AFD_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status));
153             ZwClose(*Handle);
154         } else {
155             AFD_DbgPrint(MAX_TRACE, ("Got handle (%p)  Object (%p)\n",
156                                      *Handle, *Object));
157         }
158     } else {
159         AFD_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status));
160     }
161 
162     if (!NT_SUCCESS(Status)) {
163         *Handle = INVALID_HANDLE_VALUE;
164         *Object = NULL;
165     }
166 
167     return Status;
168 }
169 
TdiOpenAddressFile(PUNICODE_STRING DeviceName,PTRANSPORT_ADDRESS Name,ULONG ShareType,PHANDLE AddressHandle,PFILE_OBJECT * AddressObject)170 NTSTATUS TdiOpenAddressFile(
171     PUNICODE_STRING DeviceName,
172     PTRANSPORT_ADDRESS Name,
173     ULONG ShareType,
174     PHANDLE AddressHandle,
175     PFILE_OBJECT *AddressObject)
176 /*
177  * FUNCTION: Opens an IPv4 address file object
178  * ARGUMENTS:
179  *     DeviceName    = Pointer to counted string with name of device
180  *     Name          = Pointer to socket name (IPv4 address family)
181  *     AddressHandle = Address of buffer to place address file handle
182  *     AddressObject = Address of buffer to place address file object
183  * RETURNS:
184  *     Status of operation
185  */
186 {
187     PFILE_FULL_EA_INFORMATION EaInfo;
188     NTSTATUS Status;
189     ULONG EaLength;
190     PTRANSPORT_ADDRESS Address;
191 
192     AFD_DbgPrint(MAX_TRACE, ("Called. DeviceName (%wZ)  Name (%p)\n",
193                              DeviceName, Name));
194 
195     /* EaName must be 0-terminated, even though TDI_TRANSPORT_ADDRESS_LENGTH does *not* include the 0 */
196     EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
197         TDI_TRANSPORT_ADDRESS_LENGTH +
198         TaLengthOfTransportAddress( Name ) + 1;
199     EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag(NonPagedPool,
200                                                               EaLength,
201                                                               TAG_AFD_EA_INFO);
202     if (!EaInfo)
203         return STATUS_INSUFFICIENT_RESOURCES;
204 
205     RtlZeroMemory(EaInfo, EaLength);
206     EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
207     /* Don't copy the terminating 0; we have already zeroed it */
208     RtlCopyMemory(EaInfo->EaName,
209                   TdiTransportAddress,
210                   TDI_TRANSPORT_ADDRESS_LENGTH);
211     EaInfo->EaValueLength = sizeof(TA_IP_ADDRESS);
212     Address =
213         (PTRANSPORT_ADDRESS)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1); /* 0-terminated */
214     TaCopyTransportAddressInPlace( Address, Name );
215 
216     Status = TdiOpenDevice(DeviceName,
217                            EaLength,
218                            EaInfo,
219                            ShareType,
220                            AddressHandle,
221                            AddressObject);
222     ExFreePoolWithTag(EaInfo, TAG_AFD_EA_INFO);
223     return Status;
224 }
225 
TdiQueryMaxDatagramLength(PFILE_OBJECT FileObject,PUINT MaxDatagramLength)226 NTSTATUS TdiQueryMaxDatagramLength(
227     PFILE_OBJECT FileObject,
228     PUINT MaxDatagramLength)
229 {
230     PMDL Mdl;
231     PTDI_MAX_DATAGRAM_INFO Buffer;
232     NTSTATUS Status = STATUS_SUCCESS;
233 
234     Buffer = ExAllocatePoolWithTag(NonPagedPool,
235                                    sizeof(TDI_MAX_DATAGRAM_INFO),
236                                    TAG_AFD_DATA_BUFFER);
237 
238     if (!Buffer) return STATUS_NO_MEMORY;
239 
240     Mdl = IoAllocateMdl(Buffer, sizeof(TDI_MAX_DATAGRAM_INFO), FALSE, FALSE, NULL);
241     if (!Mdl)
242     {
243         ExFreePoolWithTag(Buffer, TAG_AFD_DATA_BUFFER);
244         return STATUS_NO_MEMORY;
245     }
246 
247     _SEH2_TRY
248     {
249          MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
250     }
251     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
252     {
253          Status = _SEH2_GetExceptionCode();
254     }
255     _SEH2_END;
256 
257     if (!NT_SUCCESS(Status))
258     {
259         AFD_DbgPrint(MIN_TRACE,("Failed to lock pages\n"));
260         IoFreeMdl(Mdl);
261         ExFreePoolWithTag(Buffer, TAG_AFD_DATA_BUFFER);
262         return Status;
263     }
264 
265     Status = TdiQueryInformation(FileObject,
266                                  TDI_QUERY_MAX_DATAGRAM_INFO,
267                                  Mdl);
268     if (!NT_SUCCESS(Status))
269     {
270         ExFreePoolWithTag(Buffer, TAG_AFD_DATA_BUFFER);
271         return Status;
272     }
273 
274     *MaxDatagramLength = Buffer->MaxDatagramSize;
275 
276     ExFreePoolWithTag(Buffer, TAG_AFD_DATA_BUFFER);
277 
278     return STATUS_SUCCESS;
279 }
280 
TdiOpenConnectionEndpointFile(PUNICODE_STRING DeviceName,PHANDLE ConnectionHandle,PFILE_OBJECT * ConnectionObject)281 NTSTATUS TdiOpenConnectionEndpointFile(
282     PUNICODE_STRING DeviceName,
283     PHANDLE ConnectionHandle,
284     PFILE_OBJECT *ConnectionObject)
285 /*
286  * FUNCTION: Opens a connection endpoint file object
287  * ARGUMENTS:
288  *     DeviceName       = Pointer to counted string with name of device
289  *     ConnectionHandle = Address of buffer to place connection endpoint file handle
290  *     ConnectionObject = Address of buffer to place connection endpoint file object
291  * RETURNS:
292  *     Status of operation
293  */
294 {
295     PFILE_FULL_EA_INFORMATION EaInfo;
296     PVOID *ContextArea;
297     NTSTATUS Status;
298     ULONG EaLength;
299 
300     AFD_DbgPrint(MAX_TRACE, ("Called. DeviceName (%wZ)\n", DeviceName));
301 
302     /* EaName must be 0-terminated, even though TDI_TRANSPORT_ADDRESS_LENGTH does *not* include the 0 */
303     EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
304         TDI_CONNECTION_CONTEXT_LENGTH +
305         sizeof(PVOID) + 1;
306 
307     EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag(NonPagedPool,
308                                                               EaLength,
309                                                               TAG_AFD_EA_INFO);
310     if (!EaInfo)
311         return STATUS_INSUFFICIENT_RESOURCES;
312 
313     RtlZeroMemory(EaInfo, EaLength);
314     EaInfo->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
315     /* Don't copy the terminating 0; we have already zeroed it */
316     RtlCopyMemory(EaInfo->EaName,
317                   TdiConnectionContext,
318                   TDI_CONNECTION_CONTEXT_LENGTH);
319     EaInfo->EaValueLength = sizeof(PVOID);
320     ContextArea = (PVOID*)(EaInfo->EaName + TDI_CONNECTION_CONTEXT_LENGTH + 1); /* 0-terminated */
321     /* FIXME: Allocate context area */
322     *ContextArea = NULL;
323     Status = TdiOpenDevice(DeviceName,
324                            EaLength,
325                            EaInfo,
326                            AFD_SHARE_UNIQUE,
327                            ConnectionHandle,
328                            ConnectionObject);
329     ExFreePoolWithTag(EaInfo, TAG_AFD_EA_INFO);
330     return Status;
331 }
332 
333 
TdiConnect(PIRP * Irp,PFILE_OBJECT ConnectionObject,PTDI_CONNECTION_INFORMATION ConnectionCallInfo,PTDI_CONNECTION_INFORMATION ConnectionReturnInfo,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext)334 NTSTATUS TdiConnect(
335     PIRP *Irp,
336     PFILE_OBJECT ConnectionObject,
337     PTDI_CONNECTION_INFORMATION ConnectionCallInfo,
338     PTDI_CONNECTION_INFORMATION ConnectionReturnInfo,
339     PIO_COMPLETION_ROUTINE CompletionRoutine,
340     PVOID CompletionContext)
341 /*
342  * FUNCTION: Connect a connection endpoint to a remote peer
343  * ARGUMENTS:
344  *     ConnectionObject = Pointer to connection endpoint file object
345  *     RemoteAddress    = Pointer to remote address
346  * RETURNS:
347  *     Status of operation
348  */
349 {
350     PDEVICE_OBJECT DeviceObject;
351 
352     AFD_DbgPrint(MAX_TRACE, ("Called\n"));
353 
354     ASSERT(*Irp == NULL);
355 
356     if (!ConnectionObject) {
357         AFD_DbgPrint(MIN_TRACE, ("Bad connection object.\n"));
358         return STATUS_INVALID_PARAMETER;
359     }
360 
361     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
362     if (!DeviceObject) {
363         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
364         return STATUS_INVALID_PARAMETER;
365     }
366 
367     *Irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT,             /* Sub function */
368                                             DeviceObject,            /* Device object */
369                                             ConnectionObject,        /* File object */
370                                             NULL,                    /* Event */
371                                             NULL);                   /* Status */
372     if (!*Irp) {
373         return STATUS_INSUFFICIENT_RESOURCES;
374     }
375 
376     TdiBuildConnect(*Irp,                   /* IRP */
377                     DeviceObject,           /* Device object */
378                     ConnectionObject,       /* File object */
379                     CompletionRoutine,      /* Completion routine */
380                     CompletionContext,      /* Completion routine context */
381                     NULL,                   /* Time */
382                     ConnectionCallInfo,     /* Request connection information */
383                     ConnectionReturnInfo);  /* Return connection information */
384 
385     TdiCall(*Irp, DeviceObject, NULL, NULL);
386 
387     return STATUS_PENDING;
388 }
389 
390 
TdiAssociateAddressFile(HANDLE AddressHandle,PFILE_OBJECT ConnectionObject)391 NTSTATUS TdiAssociateAddressFile(
392     HANDLE AddressHandle,
393     PFILE_OBJECT ConnectionObject)
394 /*
395  * FUNCTION: Associates a connection endpoint to an address file object
396  * ARGUMENTS:
397  *     AddressHandle    = Handle to address file object
398  *     ConnectionObject = Connection endpoint file object
399  * RETURNS:
400  *     Status of operation
401  */
402 {
403     PDEVICE_OBJECT DeviceObject;
404     IO_STATUS_BLOCK Iosb;
405     KEVENT Event;
406     PIRP Irp;
407 
408     AFD_DbgPrint(MAX_TRACE, ("Called. AddressHandle (%p)  ConnectionObject (%p)\n",
409                              AddressHandle, ConnectionObject));
410 
411     if (!ConnectionObject) {
412         AFD_DbgPrint(MIN_TRACE, ("Bad connection object.\n"));
413         return STATUS_INVALID_PARAMETER;
414     }
415 
416     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
417     if (!DeviceObject) {
418         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
419         return STATUS_INVALID_PARAMETER;
420     }
421 
422     KeInitializeEvent(&Event, NotificationEvent, FALSE);
423 
424     Irp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS,   /* Sub function */
425                                            DeviceObject,            /* Device object */
426                                            ConnectionObject,        /* File object */
427                                            &Event,                  /* Event */
428                                            &Iosb);                  /* Status */
429     if (!Irp)
430         return STATUS_INSUFFICIENT_RESOURCES;
431 
432     TdiBuildAssociateAddress(Irp,
433                              DeviceObject,
434                              ConnectionObject,
435                              NULL,
436                              NULL,
437                              AddressHandle);
438 
439     return TdiCall(Irp, DeviceObject, &Event, &Iosb);
440 }
441 
TdiDisassociateAddressFile(PFILE_OBJECT ConnectionObject)442 NTSTATUS TdiDisassociateAddressFile(
443     PFILE_OBJECT ConnectionObject)
444 /*
445  * FUNCTION: Disassociates a connection endpoint from an address file object
446  * ARGUMENTS:
447  *     ConnectionObject = Connection endpoint file object
448  * RETURNS:
449  *     Status of operation
450  */
451 {
452     PDEVICE_OBJECT DeviceObject;
453     IO_STATUS_BLOCK Iosb;
454     KEVENT Event;
455     PIRP Irp;
456 
457     AFD_DbgPrint(MAX_TRACE, ("Called. ConnectionObject (%p)\n", ConnectionObject));
458 
459     if (!ConnectionObject) {
460         AFD_DbgPrint(MIN_TRACE, ("Bad connection object.\n"));
461         return STATUS_INVALID_PARAMETER;
462     }
463 
464     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
465     if (!DeviceObject) {
466         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
467         return STATUS_INVALID_PARAMETER;
468     }
469 
470     KeInitializeEvent(&Event, NotificationEvent, FALSE);
471 
472     Irp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS,   /* Sub function */
473                                            DeviceObject,            /* Device object */
474                                            ConnectionObject,        /* File object */
475                                            &Event,                  /* Event */
476                                            &Iosb);                  /* Status */
477     if (!Irp)
478         return STATUS_INSUFFICIENT_RESOURCES;
479 
480     TdiBuildDisassociateAddress(Irp,
481                                 DeviceObject,
482                                 ConnectionObject,
483                                 NULL,
484                                 NULL);
485 
486     return TdiCall(Irp, DeviceObject, &Event, &Iosb);
487 }
488 
TdiListen(PIRP * Irp,PFILE_OBJECT ConnectionObject,PTDI_CONNECTION_INFORMATION * RequestConnectionInfo,PTDI_CONNECTION_INFORMATION * ReturnConnectionInfo,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext)489 NTSTATUS TdiListen(
490     PIRP *Irp,
491     PFILE_OBJECT ConnectionObject,
492     PTDI_CONNECTION_INFORMATION *RequestConnectionInfo,
493     PTDI_CONNECTION_INFORMATION *ReturnConnectionInfo,
494     PIO_COMPLETION_ROUTINE  CompletionRoutine,
495     PVOID CompletionContext)
496 /*
497  * FUNCTION: Listen on a connection endpoint for a connection request from a remote peer
498  * ARGUMENTS:
499  *     CompletionRoutine = Routine to be called when IRP is completed
500  *     CompletionContext = Context for CompletionRoutine
501  * RETURNS:
502  *     Status of operation
503  *     May return STATUS_PENDING
504  */
505 {
506     PDEVICE_OBJECT DeviceObject;
507 
508     AFD_DbgPrint(MAX_TRACE, ("Called\n"));
509 
510     ASSERT(*Irp == NULL);
511 
512     if (!ConnectionObject) {
513         AFD_DbgPrint(MIN_TRACE, ("Bad connection object.\n"));
514         return STATUS_INVALID_PARAMETER;
515     }
516 
517     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
518     if (!DeviceObject) {
519         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
520         return STATUS_INVALID_PARAMETER;
521     }
522 
523     *Irp = TdiBuildInternalDeviceControlIrp(TDI_LISTEN,              /* Sub function */
524                                             DeviceObject,            /* Device object */
525                                             ConnectionObject,        /* File object */
526                                             NULL,                    /* Event */
527                                             NULL);                   /* Status */
528     if (*Irp == NULL)
529         return STATUS_INSUFFICIENT_RESOURCES;
530 
531     TdiBuildListen(*Irp,                   /* IRP */
532                    DeviceObject,           /* Device object */
533                    ConnectionObject,       /* File object */
534                    CompletionRoutine,      /* Completion routine */
535                    CompletionContext,      /* Completion routine context */
536                    0,                      /* Flags */
537                    *RequestConnectionInfo, /* Request connection information */
538                    *ReturnConnectionInfo);  /* Return connection information */
539 
540     TdiCall(*Irp, DeviceObject, NULL /* Don't wait for completion */, NULL);
541 
542     return STATUS_PENDING;
543 }
544 
545 
TdiSetEventHandler(PFILE_OBJECT FileObject,LONG EventType,PVOID Handler,PVOID Context)546 NTSTATUS TdiSetEventHandler(
547     PFILE_OBJECT FileObject,
548     LONG EventType,
549     PVOID Handler,
550     PVOID Context)
551 /*
552  * FUNCTION: Sets or resets an event handler
553  * ARGUMENTS:
554  *     FileObject = Pointer to file object
555  *     EventType  = Event code
556  *     Handler    = Event handler to be called when the event occurs
557  *     Context    = Context input to handler when the event occurs
558  * RETURNS:
559  *     Status of operation
560  * NOTES:
561  *     Specify NULL for Handler to stop calling event handler
562  */
563 {
564     PDEVICE_OBJECT DeviceObject;
565     IO_STATUS_BLOCK Iosb;
566     KEVENT Event;
567     PIRP Irp;
568 
569     AFD_DbgPrint(MAX_TRACE, ("Called\n"));
570 
571     if (!FileObject) {
572         AFD_DbgPrint(MIN_TRACE, ("Bad file object.\n"));
573         return STATUS_INVALID_PARAMETER;
574     }
575 
576     DeviceObject = IoGetRelatedDeviceObject(FileObject);
577     if (!DeviceObject) {
578         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
579         return STATUS_INVALID_PARAMETER;
580     }
581 
582     KeInitializeEvent(&Event, NotificationEvent, FALSE);
583 
584     Irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER,   /* Sub function */
585                                            DeviceObject,            /* Device object */
586                                            FileObject,              /* File object */
587                                            &Event,                  /* Event */
588                                            &Iosb);                  /* Status */
589     if (!Irp)
590         return STATUS_INSUFFICIENT_RESOURCES;
591 
592 
593 
594     TdiBuildSetEventHandler(Irp,
595                             DeviceObject,
596                             FileObject,
597                             NULL,
598                             NULL,
599                             EventType,
600                             Handler,
601                             Context);
602 
603     return TdiCall(Irp, DeviceObject, &Event, &Iosb);
604 }
605 
606 
TdiQueryDeviceControl(PFILE_OBJECT FileObject,ULONG IoControlCode,PVOID InputBuffer,ULONG InputBufferLength,PVOID OutputBuffer,ULONG OutputBufferLength,PULONG Return)607 NTSTATUS TdiQueryDeviceControl(
608     PFILE_OBJECT FileObject,
609     ULONG IoControlCode,
610     PVOID InputBuffer,
611     ULONG InputBufferLength,
612     PVOID OutputBuffer,
613     ULONG OutputBufferLength,
614     PULONG Return)
615 /*
616  * FUNCTION: Queries a device for information
617  * ARGUMENTS:
618  *     FileObject         = Pointer to file object
619  *     IoControlCode      = I/O control code
620  *     InputBuffer        = Pointer to buffer with input data
621  *     InputBufferLength  = Length of InputBuffer
622  *     OutputBuffer       = Address of buffer to place output data
623  *     OutputBufferLength = Length of OutputBuffer
624  * RETURNS:
625  *     Status of operation
626  */
627 {
628     PDEVICE_OBJECT DeviceObject;
629     IO_STATUS_BLOCK Iosb;
630     NTSTATUS Status;
631     KEVENT Event;
632     PIRP Irp;
633 
634     if (!FileObject) {
635         AFD_DbgPrint(MIN_TRACE, ("Bad file object.\n"));
636         return STATUS_INVALID_PARAMETER;
637     }
638 
639     DeviceObject = IoGetRelatedDeviceObject(FileObject);
640     if (!DeviceObject) {
641         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
642         return STATUS_INVALID_PARAMETER;
643     }
644 
645     KeInitializeEvent(&Event, NotificationEvent, FALSE);
646 
647     Irp = IoBuildDeviceIoControlRequest(IoControlCode,
648                                         DeviceObject,
649                                         InputBuffer,
650                                         InputBufferLength,
651                                         OutputBuffer,
652                                         OutputBufferLength,
653                                         FALSE,
654                                         &Event,
655                                         &Iosb);
656     if (!Irp)
657         return STATUS_INSUFFICIENT_RESOURCES;
658 
659     Status = TdiCall(Irp, DeviceObject, &Event, &Iosb);
660 
661     if (Return)
662         *Return = Iosb.Information;
663 
664     return Status;
665 }
666 
667 
TdiQueryInformation(PFILE_OBJECT FileObject,LONG QueryType,PMDL MdlBuffer)668 NTSTATUS TdiQueryInformation(
669     PFILE_OBJECT FileObject,
670     LONG QueryType,
671     PMDL MdlBuffer)
672 /*
673  * FUNCTION: Query for information
674  * ARGUMENTS:
675  *     FileObject   = Pointer to file object
676  *     QueryType    = Query type
677  *     MdlBuffer    = Pointer to MDL buffer specific for query type
678  * RETURNS:
679  *     Status of operation
680  */
681 {
682     PDEVICE_OBJECT DeviceObject;
683     IO_STATUS_BLOCK Iosb;
684     KEVENT Event;
685     PIRP Irp;
686 
687     if (!FileObject) {
688         AFD_DbgPrint(MIN_TRACE, ("Bad file object.\n"));
689         return STATUS_INVALID_PARAMETER;
690     }
691 
692     DeviceObject = IoGetRelatedDeviceObject(FileObject);
693     if (!DeviceObject) {
694         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
695         return STATUS_INVALID_PARAMETER;
696     }
697 
698     KeInitializeEvent(&Event, NotificationEvent, FALSE);
699 
700     Irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION,       /* Sub function */
701                                            DeviceObject,                /* Device object */
702                                            ConnectionObject,            /* File object */
703                                            &Event,                      /* Event */
704                                            &Iosb);                      /* Status */
705     if (!Irp) {
706         return STATUS_INSUFFICIENT_RESOURCES;
707     }
708 
709     TdiBuildQueryInformation(Irp,
710                              DeviceObject,
711                              FileObject,
712                              NULL,
713                              NULL,
714                              QueryType,
715                              MdlBuffer);
716 
717     return TdiCall(Irp, DeviceObject, &Event, &Iosb);
718 }
719 
TdiQueryInformationEx(PFILE_OBJECT FileObject,ULONG Entity,ULONG Instance,ULONG Class,ULONG Type,ULONG Id,PVOID OutputBuffer,PULONG OutputLength)720 NTSTATUS TdiQueryInformationEx(
721     PFILE_OBJECT FileObject,
722     ULONG Entity,
723     ULONG Instance,
724     ULONG Class,
725     ULONG Type,
726     ULONG Id,
727     PVOID OutputBuffer,
728     PULONG OutputLength)
729 /*
730  * FUNCTION: Extended query for information
731  * ARGUMENTS:
732  *     FileObject   = Pointer to file object
733  *     Entity       = Entity
734  *     Instance     = Instance
735  *     Class        = Entity class
736  *     Type         = Entity type
737  *     Id           = Entity id
738  *     OutputBuffer = Address of buffer to place data
739  *     OutputLength = Address of buffer with length of OutputBuffer (updated)
740  * RETURNS:
741  *     Status of operation
742  */
743 {
744     TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
745 
746     RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
747     QueryInfo.ID.toi_entity.tei_entity   = Entity;
748     QueryInfo.ID.toi_entity.tei_instance = Instance;
749     QueryInfo.ID.toi_class = Class;
750     QueryInfo.ID.toi_type  = Type;
751     QueryInfo.ID.toi_id    = Id;
752 
753     return TdiQueryDeviceControl(FileObject,                                /* Transport/connection object */
754                                  IOCTL_TCP_QUERY_INFORMATION_EX,            /* Control code */
755                                  &QueryInfo,                                /* Input buffer */
756                                  sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),  /* Input buffer length */
757                                  OutputBuffer,                              /* Output buffer */
758                                  *OutputLength,                             /* Output buffer length */
759                                  OutputLength);                             /* Return information */
760 }
761 
TdiQueryAddress(PFILE_OBJECT FileObject,PULONG Address)762 NTSTATUS TdiQueryAddress(
763     PFILE_OBJECT FileObject,
764     PULONG Address)
765 /*
766  * FUNCTION: Queries for a local IP address
767  * ARGUMENTS:
768  *     FileObject = Pointer to file object
769  *     Address    = Address of buffer to place local address
770  * RETURNS:
771  *     Status of operation
772  */
773 {
774     UINT i;
775     TDIEntityID *Entities;
776     ULONG EntityCount;
777     ULONG EntityType;
778     IPSNMPInfo SnmpInfo;
779     PIPADDR_ENTRY IpAddress;
780     ULONG BufferSize;
781     NTSTATUS Status = STATUS_SUCCESS;
782 
783     AFD_DbgPrint(MAX_TRACE, ("Called\n"));
784 
785     BufferSize = sizeof(TDIEntityID) * 20;
786     Entities = (TDIEntityID*)ExAllocatePoolWithTag(NonPagedPool,
787                                                    BufferSize,
788                                                    TAG_AFD_TRANSPORT_ADDRESS);
789     if (!Entities) {
790         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
791         return STATUS_INSUFFICIENT_RESOURCES;
792     }
793 
794     /* Query device for supported entities */
795 
796     Status = TdiQueryInformationEx(FileObject,          /* File object */
797                                    GENERIC_ENTITY,      /* Entity */
798                                    TL_INSTANCE,         /* Instance */
799                                    INFO_CLASS_GENERIC,  /* Entity class */
800                                    INFO_TYPE_PROVIDER,  /* Entity type */
801                                    ENTITY_LIST_ID,      /* Entity id */
802                                    Entities,            /* Output buffer */
803                                    &BufferSize);        /* Output buffer size */
804     if (!NT_SUCCESS(Status)) {
805         AFD_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status));
806         ExFreePoolWithTag(Entities, TAG_AFD_TRANSPORT_ADDRESS);
807         return Status;
808     }
809 
810     /* Locate an IP entity */
811     EntityCount = BufferSize / sizeof(TDIEntityID);
812 
813     AFD_DbgPrint(MAX_TRACE, ("EntityCount = %u\n", EntityCount));
814 
815     for (i = 0; i < EntityCount; i++) {
816         if (Entities[i].tei_entity == CL_NL_ENTITY) {
817             /* Query device for entity type */
818 
819             BufferSize = sizeof(EntityType);
820             Status = TdiQueryInformationEx(FileObject,                  /* File object */
821                                            CL_NL_ENTITY,                /* Entity */
822                                            Entities[i].tei_instance,    /* Instance */
823                                            INFO_CLASS_GENERIC,          /* Entity class */
824                                            INFO_TYPE_PROVIDER,          /* Entity type */
825                                            ENTITY_TYPE_ID,              /* Entity id */
826                                            &EntityType,                 /* Output buffer */
827                                            &BufferSize);                /* Output buffer size */
828             if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP)) {
829                 AFD_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status));
830                 break;
831             }
832 
833             /* Query device for SNMP information */
834 
835             BufferSize = sizeof(SnmpInfo);
836             Status = TdiQueryInformationEx(FileObject,                  /* File object */
837                                            CL_NL_ENTITY,                /* Entity */
838                                            Entities[i].tei_instance,    /* Instance */
839                                            INFO_CLASS_PROTOCOL,         /* Entity class */
840                                            INFO_TYPE_PROVIDER,          /* Entity type */
841                                            IP_MIB_STATS_ID,             /* Entity id */
842                                            &SnmpInfo,                   /* Output buffer */
843                                            &BufferSize);                /* Output buffer size */
844             if (!NT_SUCCESS(Status) || (SnmpInfo.ipsi_numaddr == 0)) {
845                 AFD_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status));
846                 break;
847             }
848 
849             /* Query device for all IP addresses */
850 
851             if (SnmpInfo.ipsi_numaddr != 0) {
852                 BufferSize = SnmpInfo.ipsi_numaddr * sizeof(IPADDR_ENTRY);
853                 IpAddress = (PIPADDR_ENTRY)ExAllocatePoolWithTag(NonPagedPool,
854                                                                  BufferSize,
855                                                                  TAG_AFD_SNMP_ADDRESS_INFO);
856                 if (!IpAddress) {
857                     AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
858                     break;
859                 }
860 
861                 Status = TdiQueryInformationEx(FileObject,                  /* File object */
862                                                CL_NL_ENTITY,                /* Entity */
863                                                Entities[i].tei_instance,    /* Instance */
864                                                INFO_CLASS_PROTOCOL,         /* Entity class */
865                                                INFO_TYPE_PROVIDER,          /* Entity type */
866                                                IP_MIB_ADDRTABLE_ENTRY_ID,   /* Entity id */
867                                                IpAddress,                   /* Output buffer */
868                                                &BufferSize);                /* Output buffer size */
869                 if (!NT_SUCCESS(Status)) {
870                     AFD_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status));
871                     ExFreePoolWithTag(IpAddress, TAG_AFD_SNMP_ADDRESS_INFO);
872                     break;
873                 }
874 
875                 if (SnmpInfo.ipsi_numaddr != 1) {
876                     /* Skip loopback address */
877                     *Address = DN2H(IpAddress[1].Addr);
878                 } else {
879                     /* Select the first address returned */
880                     *Address = DN2H(IpAddress->Addr);
881                 }
882 
883                 ExFreePoolWithTag(IpAddress, TAG_AFD_SNMP_ADDRESS_INFO);
884             } else {
885                 Status = STATUS_UNSUCCESSFUL;
886                 break;
887             }
888         }
889     }
890 
891     ExFreePoolWithTag(Entities, TAG_AFD_TRANSPORT_ADDRESS);
892 
893     AFD_DbgPrint(MAX_TRACE, ("Leaving\n"));
894 
895     return Status;
896 }
897 
TdiSend(PIRP * Irp,PFILE_OBJECT TransportObject,USHORT Flags,PCHAR Buffer,UINT BufferLength,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext)898 NTSTATUS TdiSend(
899     PIRP *Irp,
900     PFILE_OBJECT TransportObject,
901     USHORT Flags,
902     PCHAR Buffer,
903     UINT BufferLength,
904     PIO_COMPLETION_ROUTINE CompletionRoutine,
905     PVOID CompletionContext)
906 {
907     PDEVICE_OBJECT DeviceObject;
908     PMDL Mdl;
909 
910     ASSERT(*Irp == NULL);
911 
912     if (!TransportObject) {
913         AFD_DbgPrint(MIN_TRACE, ("Bad transport object.\n"));
914         return STATUS_INVALID_PARAMETER;
915     }
916 
917     DeviceObject = IoGetRelatedDeviceObject(TransportObject);
918     if (!DeviceObject) {
919         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
920         return STATUS_INVALID_PARAMETER;
921     }
922 
923     *Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND,                /* Sub function */
924                                             DeviceObject,            /* Device object */
925                                             TransportObject,         /* File object */
926                                             NULL,                    /* Event */
927                                             NULL);                   /* Status */
928 
929     if (!*Irp) {
930         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
931         return STATUS_INSUFFICIENT_RESOURCES;
932     }
933 
934     AFD_DbgPrint(MID_TRACE, ("Allocating irp for %p:%u\n", Buffer,BufferLength));
935 
936     Mdl = IoAllocateMdl(Buffer,         /* Virtual address */
937                         BufferLength,   /* Length of buffer */
938                         FALSE,          /* Not secondary */
939                         FALSE,          /* Don't charge quota */
940                         NULL);          /* Don't use IRP */
941     if (!Mdl) {
942         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
943         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
944         *Irp = NULL;
945         return STATUS_INSUFFICIENT_RESOURCES;
946     }
947 
948     _SEH2_TRY {
949         MmProbeAndLockPages(Mdl, (*Irp)->RequestorMode, IoReadAccess);
950     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
951         AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
952         IoFreeMdl(Mdl);
953         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
954         *Irp = NULL;
955         _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
956     } _SEH2_END;
957 
958     AFD_DbgPrint(MID_TRACE,("AFD>>> Got an MDL: %p\n", Mdl));
959 
960     TdiBuildSend(*Irp,                   /* I/O Request Packet */
961                  DeviceObject,           /* Device object */
962                  TransportObject,        /* File object */
963                  CompletionRoutine,      /* Completion routine */
964                  CompletionContext,      /* Completion context */
965                  Mdl,                    /* Data buffer */
966                  Flags,                  /* Flags */
967                  BufferLength);          /* Length of data */
968 
969     TdiCall(*Irp, DeviceObject, NULL, NULL);
970     /* Does not block...  The MDL is deleted in the receive completion
971        routine. */
972 
973     return STATUS_PENDING;
974 }
975 
TdiReceive(PIRP * Irp,PFILE_OBJECT TransportObject,USHORT Flags,PCHAR Buffer,UINT BufferLength,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext)976 NTSTATUS TdiReceive(
977     PIRP *Irp,
978     PFILE_OBJECT TransportObject,
979     USHORT Flags,
980     PCHAR Buffer,
981     UINT BufferLength,
982     PIO_COMPLETION_ROUTINE CompletionRoutine,
983     PVOID CompletionContext)
984 {
985     PDEVICE_OBJECT DeviceObject;
986     PMDL Mdl;
987 
988     ASSERT(*Irp == NULL);
989 
990     if (!TransportObject) {
991         AFD_DbgPrint(MIN_TRACE, ("Bad transport object.\n"));
992         return STATUS_INVALID_PARAMETER;
993     }
994 
995     DeviceObject = IoGetRelatedDeviceObject(TransportObject);
996     if (!DeviceObject) {
997         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
998         return STATUS_INVALID_PARAMETER;
999     }
1000 
1001     *Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE,             /* Sub function */
1002                                             DeviceObject,            /* Device object */
1003                                             TransportObject,         /* File object */
1004                                             NULL,                    /* Event */
1005                                             NULL);                   /* Status */
1006 
1007     if (!*Irp) {
1008         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1009         return STATUS_INSUFFICIENT_RESOURCES;
1010     }
1011 
1012     AFD_DbgPrint(MID_TRACE, ("Allocating irp for %p:%u\n", Buffer,BufferLength));
1013 
1014     Mdl = IoAllocateMdl(Buffer,         /* Virtual address */
1015                         BufferLength,   /* Length of buffer */
1016                         FALSE,          /* Not secondary */
1017                         FALSE,          /* Don't charge quota */
1018                         NULL);          /* Don't use IRP */
1019     if (!Mdl) {
1020         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1021         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
1022         *Irp = NULL;
1023         return STATUS_INSUFFICIENT_RESOURCES;
1024     }
1025 
1026     _SEH2_TRY {
1027         AFD_DbgPrint(MID_TRACE, ("probe and lock\n"));
1028         MmProbeAndLockPages(Mdl, (*Irp)->RequestorMode, IoModifyAccess);
1029         AFD_DbgPrint(MID_TRACE, ("probe and lock done\n"));
1030     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1031         AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
1032         IoFreeMdl(Mdl);
1033         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
1034         *Irp = NULL;
1035         _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
1036     } _SEH2_END;
1037 
1038     AFD_DbgPrint(MID_TRACE,("AFD>>> Got an MDL: %p\n", Mdl));
1039 
1040     TdiBuildReceive(*Irp,                   /* I/O Request Packet */
1041                     DeviceObject,           /* Device object */
1042                     TransportObject,        /* File object */
1043                     CompletionRoutine,      /* Completion routine */
1044                     CompletionContext,      /* Completion context */
1045                     Mdl,                    /* Data buffer */
1046                     Flags,                  /* Flags */
1047                     BufferLength);          /* Length of data */
1048 
1049 
1050     TdiCall(*Irp, DeviceObject, NULL, NULL);
1051     /* Does not block...  The MDL is deleted in the receive completion
1052        routine. */
1053 
1054     return STATUS_PENDING;
1055 }
1056 
1057 
TdiReceiveDatagram(PIRP * Irp,PFILE_OBJECT TransportObject,USHORT Flags,PCHAR Buffer,UINT BufferLength,PTDI_CONNECTION_INFORMATION Addr,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext)1058 NTSTATUS TdiReceiveDatagram(
1059     PIRP *Irp,
1060     PFILE_OBJECT TransportObject,
1061     USHORT Flags,
1062     PCHAR Buffer,
1063     UINT BufferLength,
1064     PTDI_CONNECTION_INFORMATION Addr,
1065     PIO_COMPLETION_ROUTINE CompletionRoutine,
1066     PVOID CompletionContext)
1067 /*
1068  * FUNCTION: Receives a datagram
1069  * ARGUMENTS:
1070  *     TransportObject = Pointer to transport object
1071  *     From            = Receive filter (NULL if none)
1072  *     Address         = Address of buffer to place remote address
1073  *     Buffer          = Address of buffer to place received data
1074  *     BufferSize      = Address of buffer with length of Buffer (updated)
1075  * RETURNS:
1076  *     Status of operation
1077  */
1078 {
1079     PDEVICE_OBJECT DeviceObject;
1080     PMDL Mdl;
1081 
1082     ASSERT(*Irp == NULL);
1083 
1084     if (!TransportObject) {
1085         AFD_DbgPrint(MIN_TRACE, ("Bad tranport object.\n"));
1086         return STATUS_INVALID_PARAMETER;
1087     }
1088 
1089     DeviceObject = IoGetRelatedDeviceObject(TransportObject);
1090     if (!DeviceObject) {
1091         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
1092         return STATUS_INVALID_PARAMETER;
1093     }
1094 
1095     *Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM,    /* Sub function */
1096                                             DeviceObject,            /* Device object */
1097                                             TransportObject,         /* File object */
1098                                             NULL,                    /* Event */
1099                                             NULL);                   /* Status */
1100 
1101     if (!*Irp) {
1102         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1103         return STATUS_INSUFFICIENT_RESOURCES;
1104     }
1105 
1106     AFD_DbgPrint(MID_TRACE, ("Allocating irp for %p:%u\n", Buffer,BufferLength));
1107 
1108     Mdl = IoAllocateMdl(Buffer,         /* Virtual address */
1109                         BufferLength,   /* Length of buffer */
1110                         FALSE,          /* Not secondary */
1111                         FALSE,          /* Don't charge quota */
1112                         NULL);          /* Don't use IRP */
1113     if (!Mdl) {
1114         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1115         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
1116         *Irp = NULL;
1117         return STATUS_INSUFFICIENT_RESOURCES;
1118     }
1119 
1120     _SEH2_TRY {
1121         MmProbeAndLockPages(Mdl, (*Irp)->RequestorMode, IoModifyAccess);
1122     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1123         AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
1124         IoFreeMdl(Mdl);
1125         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
1126         *Irp = NULL;
1127         _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
1128     } _SEH2_END;
1129 
1130     AFD_DbgPrint(MID_TRACE,("AFD>>> Got an MDL: %p\n", Mdl));
1131 
1132     TdiBuildReceiveDatagram(*Irp,                   /* I/O Request Packet */
1133                             DeviceObject,           /* Device object */
1134                             TransportObject,        /* File object */
1135                             CompletionRoutine,      /* Completion routine */
1136                             CompletionContext,      /* Completion context */
1137                             Mdl,                    /* Data buffer */
1138                             BufferLength,
1139                             Addr,
1140                             Addr,
1141                             Flags);                 /* Length of data */
1142 
1143     TdiCall(*Irp, DeviceObject, NULL, NULL);
1144     /* Does not block...  The MDL is deleted in the receive completion
1145        routine. */
1146 
1147     return STATUS_PENDING;
1148 }
1149 
1150 
TdiSendDatagram(PIRP * Irp,PFILE_OBJECT TransportObject,PCHAR Buffer,UINT BufferLength,PTDI_CONNECTION_INFORMATION Addr,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext)1151 NTSTATUS TdiSendDatagram(
1152     PIRP *Irp,
1153     PFILE_OBJECT TransportObject,
1154     PCHAR Buffer,
1155     UINT BufferLength,
1156     PTDI_CONNECTION_INFORMATION Addr,
1157     PIO_COMPLETION_ROUTINE CompletionRoutine,
1158     PVOID CompletionContext)
1159 /*
1160  * FUNCTION: Sends a datagram
1161  * ARGUMENTS:
1162  *     TransportObject = Pointer to transport object
1163  *     From            = Send filter (NULL if none)
1164  *     Address         = Address of buffer to place remote address
1165  *     Buffer          = Address of buffer to place send data
1166  *     BufferSize      = Address of buffer with length of Buffer (updated)
1167  * RETURNS:
1168  *     Status of operation
1169  */
1170 {
1171     PDEVICE_OBJECT DeviceObject;
1172     PMDL Mdl;
1173 
1174     ASSERT(*Irp == NULL);
1175 
1176     if (!TransportObject) {
1177         AFD_DbgPrint(MIN_TRACE, ("Bad transport object.\n"));
1178         return STATUS_INVALID_PARAMETER;
1179     }
1180 
1181     AFD_DbgPrint(MID_TRACE,("Called(TransportObject %p)\n", TransportObject));
1182 
1183     DeviceObject = IoGetRelatedDeviceObject(TransportObject);
1184     if (!DeviceObject) {
1185         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
1186         return STATUS_INVALID_PARAMETER;
1187     }
1188 
1189     if (BufferLength == 0)
1190     {
1191         AFD_DbgPrint(MID_TRACE, ("Succeeding send with length 0.\n"));
1192         return STATUS_SUCCESS;
1193     }
1194 
1195     *Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM,       /* Sub function */
1196                                             DeviceObject,            /* Device object */
1197                                             TransportObject,         /* File object */
1198                                             NULL,                    /* Event */
1199                                             NULL);                   /* Status */
1200 
1201     if (!*Irp) {
1202         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1203         return STATUS_INSUFFICIENT_RESOURCES;
1204     }
1205 
1206     AFD_DbgPrint(MID_TRACE, ("Allocating irp for %p:%u\n", Buffer,BufferLength));
1207 
1208     Mdl = IoAllocateMdl(Buffer,         /* Virtual address */
1209                         BufferLength,   /* Length of buffer */
1210                         FALSE,          /* Not secondary */
1211                         FALSE,          /* Don't charge quota */
1212                         NULL);          /* Don't use IRP */
1213 
1214     if (!Mdl) {
1215         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1216         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
1217         *Irp = NULL;
1218         return STATUS_INSUFFICIENT_RESOURCES;
1219     }
1220 
1221     _SEH2_TRY {
1222         MmProbeAndLockPages(Mdl, (*Irp)->RequestorMode, IoReadAccess);
1223     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1224         AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
1225         IoFreeMdl(Mdl);
1226         IoCompleteRequest(*Irp, IO_NO_INCREMENT);
1227         *Irp = NULL;
1228         _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
1229     } _SEH2_END;
1230 
1231     AFD_DbgPrint(MID_TRACE,("AFD>>> Got an MDL: %p\n", Mdl));
1232 
1233     TdiBuildSendDatagram(*Irp,                   /* I/O Request Packet */
1234                          DeviceObject,           /* Device object */
1235                          TransportObject,        /* File object */
1236                          CompletionRoutine,      /* Completion routine */
1237                          CompletionContext,      /* Completion context */
1238                          Mdl,                    /* Data buffer */
1239                          BufferLength,           /* Bytes to send */
1240                          Addr);                  /* Address */
1241 
1242     TdiCall(*Irp, DeviceObject, NULL, NULL);
1243     /* Does not block...  The MDL is deleted in the send completion
1244        routine. */
1245 
1246     return STATUS_PENDING;
1247 }
1248 
TdiDisconnect(PIRP * Irp,PFILE_OBJECT TransportObject,PLARGE_INTEGER Time,USHORT Flags,PIO_COMPLETION_ROUTINE CompletionRoutine,PVOID CompletionContext,PTDI_CONNECTION_INFORMATION RequestConnectionInfo,PTDI_CONNECTION_INFORMATION ReturnConnectionInfo)1249 NTSTATUS TdiDisconnect(
1250     PIRP *Irp,
1251     PFILE_OBJECT TransportObject,
1252     PLARGE_INTEGER Time,
1253     USHORT Flags,
1254     PIO_COMPLETION_ROUTINE CompletionRoutine,
1255     PVOID CompletionContext,
1256     PTDI_CONNECTION_INFORMATION RequestConnectionInfo,
1257     PTDI_CONNECTION_INFORMATION ReturnConnectionInfo) {
1258     PDEVICE_OBJECT DeviceObject;
1259 
1260     if (!TransportObject) {
1261         AFD_DbgPrint(MIN_TRACE, ("Bad transport object.\n"));
1262         return STATUS_INVALID_PARAMETER;
1263     }
1264 
1265     AFD_DbgPrint(MID_TRACE,("Called(TransportObject %p)\n", TransportObject));
1266 
1267     DeviceObject = IoGetRelatedDeviceObject(TransportObject);
1268     if (!DeviceObject) {
1269         AFD_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
1270         return STATUS_INVALID_PARAMETER;
1271     }
1272 
1273     *Irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT,          /* Sub function */
1274                                             DeviceObject,            /* Device object */
1275                                             TransportObject,         /* File object */
1276                                             NULL,                    /* Event */
1277                                             NULL);                   /* Status */
1278 
1279     if (!*Irp) {
1280         AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1281         return STATUS_INSUFFICIENT_RESOURCES;
1282     }
1283 
1284     TdiBuildDisconnect(*Irp,                   /* I/O Request Packet */
1285                        DeviceObject,           /* Device object */
1286                        TransportObject,        /* File object */
1287                        CompletionRoutine,      /* Completion routine */
1288                        CompletionContext,      /* Completion context */
1289                        Time,                   /* Time */
1290                        Flags,                  /* Disconnect flags */
1291                        RequestConnectionInfo,  /* Indication of who to disconnect */
1292                        ReturnConnectionInfo);  /* Indication of who disconnected */
1293 
1294     TdiCall(*Irp, DeviceObject, NULL, NULL);
1295 
1296     return STATUS_PENDING;
1297 }
1298 
1299 /* EOF */
1300