[httpdisk/bus] Add pre-made devices to the bus
[people/sha0/winvblock.git] / src / httpdisk / bus.c
1 /**
2  * Copyright (C) 2010-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  *
4  * This file is part of WinVBlock, originally derived from WinAoE.
5  *
6  * WinVBlock is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * WinVBlock is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file
22  *
23  * HTTPDisk bus specifics.
24  */
25
26 #include <ntddk.h>
27
28 #include "portable.h"
29 #include "winvblock.h"
30 #include "debug.h"
31 #include "dummy.h"
32 #include "bus.h"
33 #include "irp.h"
34 #include "httpdisk.h"
35
36 /** From httpdisk.c */
37 extern PDRIVER_OBJECT HttpdiskDriverObj;
38
39 /** Exports. */
40 NTSTATUS STDCALL HttpdiskBusEstablish(void);
41 VOID HttpdiskBusCleanup(void);
42 DRIVER_ADD_DEVICE HttpdiskBusAttach;
43 DRIVER_DISPATCH HttpdiskBusIrp;
44
45 /** Private. */
46 static NTSTATUS STDCALL HttpdiskBusCreateFdo_(void);
47 static NTSTATUS STDCALL HttpdiskBusCreatePdo_(void);
48 static VOID HttpdiskBusDeleteFdo_(void);
49
50 /* The HTTPDisk bus. */
51 static WVL_S_BUS_T HttpdiskBus_ = {0};
52
53 /* Names for the HTTPDisk bus. */
54 #define HTTPDISK_M_BUS_NAME_ (L"\\Device\\HTTPDisk")
55 #define HTTPDISK_M_BUS_DOSNAME_ (L"\\DosDevices\\HTTPDisk")
56 static UNICODE_STRING HttpdiskBusName_ = {
57     sizeof HTTPDISK_M_BUS_NAME_ - sizeof (WCHAR),
58     sizeof HTTPDISK_M_BUS_NAME_ - sizeof (WCHAR),
59     HTTPDISK_M_BUS_NAME_
60   };
61 static UNICODE_STRING HttpdiskBusDosname_ = {
62     sizeof HTTPDISK_M_BUS_DOSNAME_ - sizeof (WCHAR),
63     sizeof HTTPDISK_M_BUS_DOSNAME_ - sizeof (WCHAR),
64     HTTPDISK_M_BUS_DOSNAME_
65   };
66
67 NTSTATUS STDCALL HttpdiskBusEstablish(void) {
68     NTSTATUS status;
69     PDEVICE_OBJECT dev_obj = HttpdiskDriverObj->DeviceObject;
70
71     /* Initialize the bus. */
72     WvlBusInit(&HttpdiskBus_);
73     HttpdiskBus_.State = WvlBusStateStarted;
74
75     status = HttpdiskBusCreateFdo_();
76     if (!NT_SUCCESS(status))
77       goto err_fdo;
78
79     status = HttpdiskBusCreatePdo_();
80     if (!NT_SUCCESS(status))
81       goto err_pdo;
82
83     /* Add devices already created.  TODO: This will go away at some point. */
84     while (dev_obj) {
85         HTTPDISK_SP_DEV dev = dev_obj->DeviceExtension;
86
87         WvlBusInitNode(&dev->BusNode, dev_obj);
88         WvlBusAddNode(&HttpdiskBus_, &dev->BusNode);
89         dev_obj = dev_obj->NextDevice;
90       }
91
92     DBG("Bus established.\n");
93     return STATUS_SUCCESS;
94
95     HttpdiskBusDeleteFdo_();
96     err_fdo:
97
98     /* TODO: Remove the PDO. */
99     err_pdo:
100
101     DBG("Bus not established.\n");
102     return status;
103   }
104
105 VOID HttpdiskBusCleanup(void) {
106     /*
107      * The FDO should be deleted by an IRP_MJ_PNP:IRP_MN_REMOVE_DEVICE,
108      * but just in case it isn't...
109      */
110     HttpdiskBusDeleteFdo_();
111     DBG("Cleaned up.\n");
112     return;
113   }
114
115 NTSTATUS HttpdiskBusAttach(
116     IN PDRIVER_OBJECT DriverObj,
117     IN PDEVICE_OBJECT Pdo
118   ) {
119     NTSTATUS status;
120
121     /* Do we already have our bus? */
122     if (HttpdiskBus_.Pdo) {
123         DBG(
124             "Bus PDO %p already established.  Refusing...\n",
125             HttpdiskBus_.Pdo
126           );
127         status = STATUS_NOT_SUPPORTED;
128         goto err_already_established;
129       }
130     /* Associate the bus with the PDO. */
131     HttpdiskBus_.Pdo = Pdo;
132     /* Attach the FDO to the PDO. */
133     HttpdiskBus_.LowerDeviceObject = IoAttachDeviceToDeviceStack(
134         HttpdiskBus_.Fdo,
135         Pdo
136       );
137     if (HttpdiskBus_.LowerDeviceObject == NULL) {
138         status = STATUS_NO_SUCH_DEVICE;
139         DBG("IoAttachDeviceToDeviceStack() failed!\n");
140         goto err_attach;
141       }
142
143     /* Ok! */
144     DBG("Attached bus to PDO %p.\n", Pdo);
145     return STATUS_SUCCESS;
146
147     err_attach:
148
149     err_already_established:
150
151     DBG("PDO %p not attached.\n", Pdo);
152     return status;
153   }
154
155 NTSTATUS HttpdiskBusIrp(IN PDEVICE_OBJECT DevObj, IN PIRP Irp) {
156     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp);
157     UCHAR major = io_stack_loc->MajorFunction;
158     NTSTATUS status;
159
160     switch (major) {
161         case IRP_MJ_PNP:
162           status = WvlBusPnp(&HttpdiskBus_, Irp);
163           /* Is the bus still attached?  If not, it's time to stop. */
164           if (HttpdiskBus_.State == WvlBusStateDeleted)
165             HttpdiskBusDeleteFdo_();
166           return status;
167
168         case IRP_MJ_POWER:
169           return WvlBusPower(&HttpdiskBus_, Irp);
170
171         case IRP_MJ_SYSTEM_CONTROL:
172           return WvlBusSysCtl(&HttpdiskBus_, Irp);
173
174         default:
175           DBG("Unhandled major: %d\n", major);
176           break;
177       }
178     return WvlIrpComplete(Irp, 0, STATUS_NOT_SUPPORTED);
179   }
180
181 static NTSTATUS STDCALL HttpdiskBusCreateFdo_(void) {
182     NTSTATUS status;
183     HTTPDISK_SP_DEV dev;
184
185     status = IoCreateDevice(
186         HttpdiskDriverObj,
187         sizeof *dev,
188         &HttpdiskBusName_,
189         FILE_DEVICE_CONTROLLER,
190         FILE_DEVICE_SECURE_OPEN,
191         FALSE,
192         &HttpdiskBus_.Fdo
193       );
194     if (!NT_SUCCESS(status)) {
195         DBG("FDO not created.\n");
196         return status;
197       }
198
199     /* Initialize device extension. */
200     dev = HttpdiskBus_.Fdo->DeviceExtension;
201     dev->bus = TRUE;
202
203     DBG("FDO created: %p.\n", (PVOID) HttpdiskBus_.Fdo);
204     return STATUS_SUCCESS;
205   }
206
207 static NTSTATUS STDCALL HttpdiskBusCreatePdo_(void) {
208     NTSTATUS status;
209
210     /* Generate dummy IDs for the HTTPDisk bus PDO. */
211     WV_M_DUMMY_ID_GEN(
212         static const,
213         HttpdiskBusDummyIds_,
214         WVL_M_WLIT L"\\HTTPDisk",
215         L"0",
216         WVL_M_WLIT L"\\HTTPDisk\0",
217         WVL_M_WLIT L"\\HTTPDisk\0",
218         FILE_DEVICE_CONTROLLER,
219         FILE_DEVICE_SECURE_OPEN
220       );
221
222     status = WvDummyAdd(&HttpdiskBusDummyIds_.DummyIds);
223     if (!NT_SUCCESS(status)) {
224         DBG("PDO not created.\n");
225         return status;
226       }
227
228     DBG("PDO created.\n");
229     return STATUS_SUCCESS;
230   }
231
232 static VOID HttpdiskBusDeleteFdo_(void) {
233     if (!HttpdiskBus_.Fdo)
234       return;
235     IoDeleteDevice(HttpdiskBus_.Fdo);
236     DBG("FDO %p deleted.\n", (PVOID) HttpdiskBus_.Fdo);
237     HttpdiskBus_.Fdo = NULL;
238     return;
239   }