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