Revert "[httpdisk] Apply WinVBlock-as-usual indentation"
[people/sha0/winvblock.git] / src / httpdisk / ktdi.c
1 /*
2     HTTP Virtual Disk.
3     Copyright (C) 2006 Bo Brantén.
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12     You should have received a copy of the GNU General Public License
13     along with this program; if not, write to the Free Software
14     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15 */
16
17 #include <ntddk.h>
18 #include <tdikrnl.h>
19 #include "ktdi.h"
20
21 NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, BOOLEAN shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject)
22 {
23     OBJECT_ATTRIBUTES           attr;
24     PFILE_FULL_EA_INFORMATION   eaBuffer;
25     ULONG                       eaSize;
26     PTA_IP_ADDRESS              localAddr;
27     IO_STATUS_BLOCK             iosb;
28     NTSTATUS                    status;
29
30 #if (VER_PRODUCTBUILD >= 2195)
31     InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
32 #else
33     InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);
34 #endif
35
36     eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
37              TDI_TRANSPORT_ADDRESS_LENGTH                      +
38              1                                                 +
39              sizeof(TA_IP_ADDRESS);
40
41     eaBuffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPool, eaSize);
42
43     if (eaBuffer == NULL)
44     {
45         return STATUS_INSUFFICIENT_RESOURCES;
46     }
47
48     eaBuffer->NextEntryOffset = 0;
49     eaBuffer->Flags = 0;
50     eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
51     eaBuffer->EaValueLength = sizeof(TA_IP_ADDRESS);
52
53     RtlCopyMemory(eaBuffer->EaName, TdiTransportAddress, eaBuffer->EaNameLength + 1);
54
55     localAddr = (PTA_IP_ADDRESS)(eaBuffer->EaName + eaBuffer->EaNameLength + 1);
56
57     localAddr->TAAddressCount = 1;
58     localAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
59     localAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
60     localAddr->Address[0].Address[0].sin_port = port;
61     localAddr->Address[0].Address[0].in_addr = addr;
62
63     RtlZeroMemory(localAddr->Address[0].Address[0].sin_zero, sizeof(localAddr->Address[0].Address[0].sin_zero));
64
65     status = ZwCreateFile(
66         addressHandle,
67         GENERIC_READ | GENERIC_WRITE,
68         &attr,
69         &iosb,
70         NULL,
71         FILE_ATTRIBUTE_NORMAL,
72         shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
73         FILE_OPEN,
74         0,
75         eaBuffer,
76         eaSize
77         );
78
79     ExFreePool(eaBuffer);
80
81     if (!NT_SUCCESS(status))
82     {
83         return status;
84     }
85
86     status = ObReferenceObjectByHandle(*addressHandle, FILE_ALL_ACCESS, NULL, KernelMode, addressFileObject, NULL);
87
88     if (!NT_SUCCESS(status))
89     {
90         ZwClose(*addressHandle);
91         return status;
92     }
93
94     return STATUS_SUCCESS;
95 }
96
97 NTSTATUS tdi_open_connection_endpoint(PUNICODE_STRING devName, PVOID connectionContext, BOOLEAN shared, PHANDLE connectionHandle, PFILE_OBJECT *connectionFileObject)
98 {
99     OBJECT_ATTRIBUTES           attr;
100     PFILE_FULL_EA_INFORMATION   eaBuffer;
101     ULONG                       eaSize;
102     PVOID                       *context;
103     IO_STATUS_BLOCK             iosb;
104     NTSTATUS                    status;
105
106 #if (VER_PRODUCTBUILD >= 2195)
107     InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
108 #else
109     InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);
110 #endif
111
112     eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
113              TDI_CONNECTION_CONTEXT_LENGTH                     +
114              1                                                 +
115              sizeof(int);
116
117     eaBuffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPool, eaSize);
118
119     if (eaBuffer == NULL)
120     {
121         return STATUS_INSUFFICIENT_RESOURCES;
122     }
123
124     eaBuffer->NextEntryOffset = 0;
125     eaBuffer->Flags = 0;
126     eaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
127     eaBuffer->EaValueLength = sizeof(int);
128
129     RtlCopyMemory(eaBuffer->EaName, TdiConnectionContext, eaBuffer->EaNameLength + 1);
130
131     context = (PVOID*) &(eaBuffer->EaName[eaBuffer->EaNameLength + 1]);
132
133     *context = connectionContext;
134
135     status = ZwCreateFile(
136         connectionHandle,
137         GENERIC_READ | GENERIC_WRITE,
138         &attr,
139         &iosb,
140         NULL,
141         FILE_ATTRIBUTE_NORMAL,
142         shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
143         FILE_OPEN,
144         0,
145         eaBuffer,
146         eaSize
147         );
148
149     ExFreePool(eaBuffer);
150
151     if (!NT_SUCCESS(status))
152     {
153         return status;
154     }
155
156     status = ObReferenceObjectByHandle(*connectionHandle, FILE_ALL_ACCESS, NULL, KernelMode, connectionFileObject, NULL);
157
158     if (!NT_SUCCESS(status))
159     {
160         ZwClose(*connectionHandle);
161         return status;
162     }
163
164     return STATUS_SUCCESS;
165 }
166
167 NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext)
168 {
169     PDEVICE_OBJECT  devObj;
170     KEVENT          event;
171     PIRP            irp;
172     IO_STATUS_BLOCK iosb;
173     NTSTATUS        status;
174
175     devObj = IoGetRelatedDeviceObject(addressFileObject);
176
177     KeInitializeEvent(&event, NotificationEvent, FALSE);
178
179     irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, devObj, addressFileObject, &event, &iosb);
180
181     if (irp == NULL)
182     {
183         return STATUS_INSUFFICIENT_RESOURCES;
184     }
185
186     TdiBuildSetEventHandler(irp, devObj, addressFileObject, NULL, NULL, eventType, eventHandler, eventContext);
187
188     status = IoCallDriver(devObj, irp);
189
190     if (status == STATUS_PENDING)
191     {
192         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
193         status = iosb.Status;
194     }
195
196     return status;
197 }
198
199 NTSTATUS tdi_unset_event_handler(PFILE_OBJECT addressFileObject, LONG eventType)
200 {
201     return tdi_set_event_handler(addressFileObject, eventType, NULL, NULL);
202 }
203
204 NTSTATUS tdi_associate_address(PFILE_OBJECT connectionFileObject, HANDLE addressHandle)
205 {
206     PDEVICE_OBJECT  devObj;
207     KEVENT          event;
208     PIRP            irp;
209     IO_STATUS_BLOCK iosb;
210     NTSTATUS        status;
211
212     devObj = IoGetRelatedDeviceObject(connectionFileObject);
213
214     KeInitializeEvent(&event, NotificationEvent, FALSE);
215
216     irp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);
217
218     if (irp == NULL)
219     {
220         return STATUS_INSUFFICIENT_RESOURCES;
221     }
222
223     TdiBuildAssociateAddress(irp, devObj, connectionFileObject, NULL, NULL, addressHandle);
224
225     status = IoCallDriver(devObj, irp);
226
227     if (status == STATUS_PENDING)
228     {
229         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
230         status = iosb.Status;
231     }
232
233     return status;
234 }
235
236 NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject)
237 {
238     PDEVICE_OBJECT  devObj;
239     KEVENT          event;
240     PIRP            irp;
241     IO_STATUS_BLOCK iosb;
242     NTSTATUS        status;
243
244     devObj = IoGetRelatedDeviceObject(connectionFileObject);
245
246     KeInitializeEvent(&event, NotificationEvent, FALSE);
247
248     irp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);
249
250     if (irp == NULL)
251     {
252         return STATUS_INSUFFICIENT_RESOURCES;
253     }
254
255     TdiBuildDisassociateAddress(irp, devObj, connectionFileObject, NULL, NULL);
256
257     status = IoCallDriver(devObj, irp);
258
259     if (status == STATUS_PENDING)
260     {
261         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
262         status = iosb.Status;
263     }
264
265     return status;
266 }
267
268 NTSTATUS tdi_connect(PFILE_OBJECT connectionFileObject, ULONG addr, USHORT port)
269 {
270     PDEVICE_OBJECT              devObj;
271     KEVENT                      event;
272     PTDI_CONNECTION_INFORMATION remoteInfo;
273     PTA_IP_ADDRESS              remoteAddr;
274     PTDI_CONNECTION_INFORMATION returnInfo;
275     PTA_IP_ADDRESS              returnAddr;
276     PIRP                        irp;
277     IO_STATUS_BLOCK             iosb;
278     NTSTATUS                    status;
279
280     devObj = IoGetRelatedDeviceObject(connectionFileObject);
281
282     KeInitializeEvent(&event, NotificationEvent, FALSE);
283
284     remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + 2 * sizeof(TA_IP_ADDRESS));
285
286     if (remoteInfo == NULL)
287     {
288         return STATUS_INSUFFICIENT_RESOURCES;
289     }
290
291     RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + 2 * sizeof(TA_IP_ADDRESS));
292
293     remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
294     remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);
295
296     remoteAddr = (PTA_IP_ADDRESS) remoteInfo->RemoteAddress;
297
298     remoteAddr->TAAddressCount = 1;
299     remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
300     remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
301     remoteAddr->Address[0].Address[0].sin_port = port;
302     remoteAddr->Address[0].Address[0].in_addr = addr;
303
304     returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
305
306     returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
307     returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);
308
309     returnAddr = (PTA_IP_ADDRESS) returnInfo->RemoteAddress;
310
311     returnAddr->TAAddressCount = 1;
312     returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
313     returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
314
315     irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT, devObj, connectionFileObject, &event, &iosb);
316
317     if (irp == NULL)
318     {
319         ExFreePool(remoteInfo);
320         return STATUS_INSUFFICIENT_RESOURCES;
321     }
322
323     TdiBuildConnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, remoteInfo, returnInfo);
324
325     status = IoCallDriver(devObj, irp);
326
327     if (status == STATUS_PENDING)
328     {
329         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
330         status = iosb.Status;
331     }
332
333     ExFreePool(remoteInfo);
334
335     return status;
336 }
337
338 NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags)
339 {
340     PDEVICE_OBJECT  devObj;
341     KEVENT          event;
342     PIRP            irp;
343     IO_STATUS_BLOCK iosb;
344     NTSTATUS        status;
345
346     devObj = IoGetRelatedDeviceObject(connectionFileObject);
347
348     KeInitializeEvent(&event, NotificationEvent, FALSE);
349
350     irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT, devObj, connectionFileObject, &event, &iosb);
351
352     if (irp == NULL)
353     {
354         return STATUS_INSUFFICIENT_RESOURCES;
355     }
356
357     TdiBuildDisconnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, flags, NULL, NULL);
358
359     status = IoCallDriver(devObj, irp);
360
361     if (status == STATUS_PENDING)
362     {
363         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
364         status = iosb.Status;
365     }
366
367     return status;
368 }
369
370 NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len)
371 {
372     PDEVICE_OBJECT              devObj;
373     KEVENT                      event;
374     PTDI_CONNECTION_INFORMATION remoteInfo;
375     PTA_IP_ADDRESS              remoteAddr;
376     PIRP                        irp;
377     PMDL                        mdl;
378     IO_STATUS_BLOCK             iosb;
379     NTSTATUS                    status;
380
381     devObj = IoGetRelatedDeviceObject(addressFileObject);
382
383     KeInitializeEvent(&event, NotificationEvent, FALSE);
384
385     remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
386
387     if (remoteInfo == NULL)
388     {
389         return STATUS_INSUFFICIENT_RESOURCES;
390     }
391
392     RtlZeroMemory(remoteInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
393
394     remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
395     remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);
396
397     remoteAddr = (PTA_IP_ADDRESS) remoteInfo->RemoteAddress;
398
399     remoteAddr->TAAddressCount = 1;
400     remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
401     remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
402     remoteAddr->Address[0].Address[0].sin_port = port;
403     remoteAddr->Address[0].Address[0].in_addr = addr;
404
405     irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, devObj, addressFileObject, &event, &iosb);
406
407     if (irp == NULL)
408     {
409         ExFreePool(remoteInfo);
410         return STATUS_INSUFFICIENT_RESOURCES;
411     }
412
413     if (len)
414     {
415         mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
416
417         if (mdl == NULL)
418         {
419             IoFreeIrp(irp);
420             ExFreePool(remoteInfo);
421             return STATUS_INSUFFICIENT_RESOURCES;
422         }
423
424         __try
425         {
426             MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
427             status = STATUS_SUCCESS;
428         }
429         __except (EXCEPTION_EXECUTE_HANDLER)
430         {
431             IoFreeMdl(mdl);
432             IoFreeIrp(irp);
433             ExFreePool(remoteInfo);
434             status = STATUS_INVALID_USER_BUFFER;
435         }
436
437         if (!NT_SUCCESS(status))
438         {
439             return status;
440         }
441     }
442
443     TdiBuildSendDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo);
444
445     status = IoCallDriver(devObj, irp);
446
447     if (status == STATUS_PENDING)
448     {
449         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
450         status = iosb.Status;
451     }
452
453     ExFreePool(remoteInfo);
454
455     return NT_SUCCESS(status) ? iosb.Information : status;
456 }
457
458 NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags)
459 {
460     PDEVICE_OBJECT              devObj;
461     KEVENT                      event;
462     PTDI_CONNECTION_INFORMATION remoteInfo;
463     PTDI_CONNECTION_INFORMATION returnInfo;
464     PTA_IP_ADDRESS              returnAddr;
465     PIRP                        irp;
466     PMDL                        mdl;
467     IO_STATUS_BLOCK             iosb;
468     NTSTATUS                    status;
469
470     devObj = IoGetRelatedDeviceObject(addressFileObject);
471
472     KeInitializeEvent(&event, NotificationEvent, FALSE);
473
474     remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
475
476     if (remoteInfo == NULL)
477     {
478         return STATUS_INSUFFICIENT_RESOURCES;
479     }
480
481     RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
482
483     remoteInfo->RemoteAddressLength = 0;
484     remoteInfo->RemoteAddress = NULL;
485
486     returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION));
487
488     returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
489     returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);
490
491     returnAddr = (PTA_IP_ADDRESS) returnInfo->RemoteAddress;
492
493     returnAddr->TAAddressCount = 1;
494     returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
495     returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
496
497     irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, devObj, addressFileObject, &event, &iosb);
498
499     if (irp == NULL)
500     {
501         ExFreePool(remoteInfo);
502         return STATUS_INSUFFICIENT_RESOURCES;
503     }
504
505     if (len)
506     {
507         mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
508
509         if (mdl == NULL)
510         {
511             IoFreeIrp(irp);
512             ExFreePool(remoteInfo);
513             return STATUS_INSUFFICIENT_RESOURCES;
514         }
515
516         __try
517         {
518             MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
519             status = STATUS_SUCCESS;
520         }
521         __except (EXCEPTION_EXECUTE_HANDLER)
522         {
523             IoFreeMdl(mdl);
524             IoFreeIrp(irp);
525             ExFreePool(remoteInfo);
526             status = STATUS_INVALID_USER_BUFFER;
527         }
528
529         if (!NT_SUCCESS(status))
530         {
531             return status;
532         }
533     }
534
535     TdiBuildReceiveDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo, returnInfo, flags);
536
537     status = IoCallDriver(devObj, irp);
538
539     if (status == STATUS_PENDING)
540     {
541         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
542         status = iosb.Status;
543     }
544
545     if (addr)
546     {
547         *addr = returnAddr->Address[0].Address[0].in_addr;
548     }
549
550     if (port)
551     {
552         *port = returnAddr->Address[0].Address[0].sin_port;
553     }
554
555     ExFreePool(remoteInfo);
556
557     return NT_SUCCESS(status) ? iosb.Information : status;
558 }
559
560 NTSTATUS tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags)
561 {
562     PDEVICE_OBJECT  devObj;
563     KEVENT          event;
564     PIRP            irp;
565     PMDL            mdl;
566     IO_STATUS_BLOCK iosb;
567     NTSTATUS        status;
568
569     devObj = IoGetRelatedDeviceObject(connectionFileObject);
570
571     KeInitializeEvent(&event, NotificationEvent, FALSE);
572
573     irp = TdiBuildInternalDeviceControlIrp(TDI_SEND, devObj, connectionFileObject, &event, &iosb);
574
575     if (irp == NULL)
576     {
577         return STATUS_INSUFFICIENT_RESOURCES;
578     }
579
580     if (len)
581     {
582         mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
583
584         if (mdl == NULL)
585         {
586             IoFreeIrp(irp);
587             return STATUS_INSUFFICIENT_RESOURCES;
588         }
589
590         __try
591         {
592             MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
593             status = STATUS_SUCCESS;
594         }
595         __except (EXCEPTION_EXECUTE_HANDLER)
596         {
597             IoFreeMdl(mdl);
598             IoFreeIrp(irp);
599             status = STATUS_INVALID_USER_BUFFER;
600         }
601
602         if (!NT_SUCCESS(status))
603         {
604             return status;
605         }
606     }
607
608     TdiBuildSend(irp, devObj, connectionFileObject, NULL, NULL, len ? mdl : 0, flags, len);
609
610     status = IoCallDriver(devObj, irp);
611
612     if (status == STATUS_PENDING)
613     {
614         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
615         status = iosb.Status;
616     }
617
618     return NT_SUCCESS(status) ? iosb.Information : status;
619 }
620
621 NTSTATUS tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags)
622 {
623     PDEVICE_OBJECT  devObj;
624     KEVENT          event;
625     PIRP            irp;
626     PMDL            mdl;
627     IO_STATUS_BLOCK iosb;
628     NTSTATUS        status;
629
630     devObj = IoGetRelatedDeviceObject(connectionFileObject);
631
632     KeInitializeEvent(&event, NotificationEvent, FALSE);
633
634     irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE, devObj, connectionFileObject, &event, &iosb);
635
636     if (irp == NULL)
637     {
638         return STATUS_INSUFFICIENT_RESOURCES;
639     }
640
641     if (len)
642     {
643         mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
644
645         if (mdl == NULL)
646         {
647             IoFreeIrp(irp);
648             return STATUS_INSUFFICIENT_RESOURCES;
649         }
650
651         __try
652         {
653             MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
654             status = STATUS_SUCCESS;
655         }
656         __except (EXCEPTION_EXECUTE_HANDLER)
657         {
658             IoFreeMdl(mdl);
659             IoFreeIrp(irp);
660             status = STATUS_INVALID_USER_BUFFER;
661         }
662
663         if (!NT_SUCCESS(status))
664         {
665             return status;
666         }
667     }
668
669     TdiBuildReceive(irp, devObj, connectionFileObject, NULL, NULL, len ? mdl : 0, flags, len);
670
671     status = IoCallDriver(devObj, irp);
672
673     if (status == STATUS_PENDING)
674     {
675         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
676         status = iosb.Status;
677     }
678
679     return NT_SUCCESS(status) ? iosb.Information : status;
680 }
681
682 NTSTATUS tdi_query_address(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port)
683 {
684     PDEVICE_OBJECT              devObj;
685     KEVENT                      event;
686     PTRANSPORT_ADDRESS          localInfo;
687     PTA_IP_ADDRESS              localAddr;
688     PIRP                        irp;
689     PMDL                        mdl;
690     IO_STATUS_BLOCK             iosb;
691     NTSTATUS                    status;
692
693     devObj = IoGetRelatedDeviceObject(addressFileObject);
694
695     KeInitializeEvent(&event, NotificationEvent, FALSE);
696
697     localInfo = (PTRANSPORT_ADDRESS) ExAllocatePool(NonPagedPool, sizeof(TDI_ADDRESS_INFO)*10);
698
699     if (localInfo == NULL)
700     {
701         return STATUS_INSUFFICIENT_RESOURCES;
702     }
703
704     RtlZeroMemory(localInfo, sizeof(TDI_ADDRESS_INFO)*10);
705
706     irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, devObj, addressFileObject, &event, &iosb);
707
708     if (irp == NULL)
709     {
710         ExFreePool(localInfo);
711         return STATUS_INSUFFICIENT_RESOURCES;
712     }
713
714     {
715         mdl = IoAllocateMdl((void*) localInfo, sizeof(TDI_ADDRESS_INFO)*10, FALSE, FALSE, NULL);
716
717         if (mdl == NULL)
718         {
719             IoFreeIrp(irp);
720             ExFreePool(localInfo);
721             return STATUS_INSUFFICIENT_RESOURCES;
722         }
723
724         __try
725         {
726             MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
727             status = STATUS_SUCCESS;
728         }
729         __except (EXCEPTION_EXECUTE_HANDLER)
730         {
731             IoFreeMdl(mdl);
732             IoFreeIrp(irp);
733             ExFreePool(localInfo);
734             status = STATUS_INVALID_USER_BUFFER;
735         }
736
737         if (!NT_SUCCESS(status))
738         {
739             return status;
740         }
741     }
742
743     TdiBuildQueryInformation(irp, devObj, addressFileObject, NULL, NULL, TDI_QUERY_ADDRESS_INFO, mdl);
744
745     status = IoCallDriver(devObj, irp);
746
747     if (status == STATUS_PENDING)
748     {
749         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
750         status = iosb.Status;
751     }
752
753     localAddr = (PTA_IP_ADDRESS)&localInfo->Address[0];
754
755     if (addr)
756     {
757         *addr = localAddr->Address[0].Address[0].in_addr;
758     }
759
760     if (port)
761     {
762         *port = localAddr->Address[0].Address[0].sin_port;
763     }
764
765     ExFreePool(localInfo);
766
767     return status;
768 }