1 /*
2 Driver for USB RNDIS Network devices
3 Copyright (C) 2022 Adrien Destugues <pulkomandy@pulkomandy.tk>
4 Distributed under the terms of the MIT license.
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <lock.h>
10
11 #include "Driver.h"
12 #include "RNDISDevice.h"
13
14 int32 api_version = B_CUR_DRIVER_API_VERSION;
15 static const char *sDeviceBaseName = "net/usb_rndis/";
16 RNDISDevice *gRNDISDevices[MAX_DEVICES];
17 char *gDeviceNames[MAX_DEVICES + 1];
18 usb_module_info *gUSBModule = NULL;
19 mutex gDriverLock;
20
21
22 status_t
usb_rndis_device_added(usb_device device,void ** cookie)23 usb_rndis_device_added(usb_device device, void **cookie)
24 {
25 *cookie = NULL;
26
27 // check if this is a replug of an existing device first
28 mutex_lock(&gDriverLock);
29
30 // no such device yet, create a new one
31 RNDISDevice *rndisDevice = new RNDISDevice(device);
32 status_t status = rndisDevice->InitCheck();
33 if (status < B_OK) {
34 delete rndisDevice;
35 mutex_unlock(&gDriverLock);
36 return status;
37 }
38
39 for (int32 i = 0; i < MAX_DEVICES; i++) {
40 if (gRNDISDevices[i] != NULL)
41 continue;
42
43 gRNDISDevices[i] = rndisDevice;
44 *cookie = rndisDevice;
45
46 TRACE_ALWAYS("rndis device %" B_PRId32 " added\n", i);
47 mutex_unlock(&gDriverLock);
48 return B_OK;
49 }
50
51 // no space for the device
52 delete rndisDevice;
53 mutex_unlock(&gDriverLock);
54 return B_ERROR;
55 }
56
57
58 status_t
usb_rndis_device_removed(void * cookie)59 usb_rndis_device_removed(void *cookie)
60 {
61 mutex_lock(&gDriverLock);
62
63 RNDISDevice *device = (RNDISDevice *)cookie;
64 for (int32 i = 0; i < MAX_DEVICES; i++) {
65 if (gRNDISDevices[i] == device) {
66 if (device->IsOpen()) {
67 // the device will be deleted upon being freed
68 device->Removed();
69 } else {
70 gRNDISDevices[i] = NULL;
71 delete device;
72 }
73 break;
74 }
75 }
76
77 mutex_unlock(&gDriverLock);
78 return B_OK;
79 }
80
81
82 //#pragma mark -
83
84
85 status_t
init_hardware()86 init_hardware()
87 {
88 TRACE("init_hardware()\n");
89 return B_OK;
90 }
91
92
93 status_t
init_driver()94 init_driver()
95 {
96 TRACE("init_driver()\n");
97 status_t status = get_module(B_USB_MODULE_NAME,
98 (module_info **)&gUSBModule);
99 if (status < B_OK)
100 return status;
101
102 for (int32 i = 0; i < MAX_DEVICES; i++)
103 gRNDISDevices[i] = NULL;
104
105 gDeviceNames[0] = NULL;
106 mutex_init(&gDriverLock, DRIVER_NAME"_devices");
107
108 static usb_notify_hooks notifyHooks = {
109 &usb_rndis_device_added,
110 &usb_rndis_device_removed
111 };
112
113 static usb_support_descriptor supportDescriptor = {
114 0xE0, /* CDC - Wireless device */
115 0x01, 0x03, /* RNDIS subclass/protocol */
116 0, 0 /* no specific vendor or device */
117 };
118
119 gUSBModule->register_driver(DRIVER_NAME, &supportDescriptor, 1, NULL);
120 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks);
121 return B_OK;
122 }
123
124
125 void
uninit_driver()126 uninit_driver()
127 {
128 TRACE("uninit_driver()\n");
129 gUSBModule->uninstall_notify(DRIVER_NAME);
130 mutex_lock(&gDriverLock);
131
132 for (int32 i = 0; i < MAX_DEVICES; i++) {
133 if (gRNDISDevices[i] != NULL) {
134 delete gRNDISDevices[i];
135 gRNDISDevices[i] = NULL;
136 }
137 }
138
139 for (int32 i = 0; gDeviceNames[i]; i++) {
140 free(gDeviceNames[i]);
141 gDeviceNames[i] = NULL;
142 }
143
144 mutex_destroy(&gDriverLock);
145 put_module(B_USB_MODULE_NAME);
146 }
147
148
149 static status_t
usb_rndis_open(const char * name,uint32 flags,void ** cookie)150 usb_rndis_open(const char *name, uint32 flags, void **cookie)
151 {
152 TRACE("open(%s, %" B_PRIu32 ", %p)\n", name, flags, cookie);
153 mutex_lock(&gDriverLock);
154
155 *cookie = NULL;
156 status_t status = ENODEV;
157 int32 index = strtol(name + strlen(sDeviceBaseName), NULL, 10);
158 if (index >= 0 && index < MAX_DEVICES && gRNDISDevices[index] != NULL) {
159 status = gRNDISDevices[index]->Open();
160 if (status == B_OK)
161 *cookie = gRNDISDevices[index];
162 }
163
164 mutex_unlock(&gDriverLock);
165 return status;
166 }
167
168
169 static status_t
usb_rndis_read(void * cookie,off_t position,void * buffer,size_t * numBytes)170 usb_rndis_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
171 {
172 TRACE("read(%p, %" B_PRIdOFF ", %p, %lu)\n", cookie, position, buffer, *numBytes);
173 RNDISDevice *device = (RNDISDevice *)cookie;
174 return device->Read((uint8 *)buffer, numBytes);
175 }
176
177
178 static status_t
usb_rndis_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)179 usb_rndis_write(void *cookie, off_t position, const void *buffer,
180 size_t *numBytes)
181 {
182 TRACE("write(%p, %" B_PRIdOFF ", %p, %lu)\n", cookie, position, buffer, *numBytes);
183 RNDISDevice *device = (RNDISDevice *)cookie;
184 return device->Write((const uint8 *)buffer, numBytes);
185 }
186
187
188 static status_t
usb_rndis_control(void * cookie,uint32 op,void * buffer,size_t length)189 usb_rndis_control(void *cookie, uint32 op, void *buffer, size_t length)
190 {
191 TRACE("control(%p, %" B_PRIu32 ", %p, %lu)\n", cookie, op, buffer, length);
192 RNDISDevice *device = (RNDISDevice *)cookie;
193 return device->Control(op, buffer, length);
194 }
195
196
197 static status_t
usb_rndis_close(void * cookie)198 usb_rndis_close(void *cookie)
199 {
200 TRACE("close(%p)\n", cookie);
201 RNDISDevice *device = (RNDISDevice *)cookie;
202 return device->Close();
203 }
204
205
206 static status_t
usb_rndis_free(void * cookie)207 usb_rndis_free(void *cookie)
208 {
209 TRACE("free(%p)\n", cookie);
210 RNDISDevice *device = (RNDISDevice *)cookie;
211 mutex_lock(&gDriverLock);
212 status_t status = device->Free();
213 for (int32 i = 0; i < MAX_DEVICES; i++) {
214 if (gRNDISDevices[i] == device) {
215 // the device is removed already but as it was open the
216 // removed hook has not deleted the object
217 gRNDISDevices[i] = NULL;
218 delete device;
219 break;
220 }
221 }
222
223 mutex_unlock(&gDriverLock);
224 return status;
225 }
226
227
228 const char **
publish_devices()229 publish_devices()
230 {
231 TRACE("publish_devices()\n");
232 for (int32 i = 0; gDeviceNames[i]; i++) {
233 free(gDeviceNames[i]);
234 gDeviceNames[i] = NULL;
235 }
236
237 int32 deviceCount = 0;
238 mutex_lock(&gDriverLock);
239 for (int32 i = 0; i < MAX_DEVICES; i++) {
240 if (gRNDISDevices[i] == NULL)
241 continue;
242
243 gDeviceNames[deviceCount] = (char *)malloc(strlen(sDeviceBaseName) + 4);
244 if (gDeviceNames[deviceCount] != NULL) {
245 sprintf(gDeviceNames[deviceCount], "%s%" B_PRId32, sDeviceBaseName,
246 i);
247 TRACE("publishing %s\n", gDeviceNames[deviceCount]);
248 deviceCount++;
249 } else
250 TRACE_ALWAYS("publish_devices - no memory to allocate device name\n");
251 }
252
253 gDeviceNames[deviceCount] = NULL;
254 mutex_unlock(&gDriverLock);
255 return (const char **)&gDeviceNames[0];
256 }
257
258
259 device_hooks *
find_device(const char * name)260 find_device(const char *name)
261 {
262 TRACE("find_device(%s)\n", name);
263 static device_hooks deviceHooks = {
264 usb_rndis_open,
265 usb_rndis_close,
266 usb_rndis_free,
267 usb_rndis_control,
268 usb_rndis_read,
269 usb_rndis_write,
270 NULL, /* select */
271 NULL /* deselect */
272 };
273
274 return &deviceHooks;
275 }
276