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