xref: /haiku/src/add-ons/kernel/drivers/network/ether/usb_rndis/Driver.cpp (revision 9548274ed50bcd9ee706faf41746c755980596a9)
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, &notifyHooks);
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