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