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