[AFD] Introduce and use pool tags. Thanks go to Arty for assisting me with this....
[reactos.git] / drivers / network / 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 */