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