xref: /haiku/src/libs/compat/freebsd_network/device.c (revision 93a78ecaa45114d68952d08c4778f073515102f2)
1 /*
2  * Copyright 2007, Hugo Santos. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Hugo Santos, hugosantos@gmail.com
7  *
8  * Some of this code is based on previous work by Marcus Overhagen.
9  */
10 
11 #include "device.h"
12 
13 #include <stdlib.h>
14 #include <Drivers.h>
15 #include <ether_driver.h>
16 
17 #include <sys/sockio.h>
18 
19 #include <compat/sys/haiku-module.h>
20 
21 #include <compat/sys/bus.h>
22 #include <compat/sys/mbuf.h>
23 #include <compat/net/ethernet.h>
24 
25 
26 #define MAX_DEVICES		8
27 
28 
29 struct network_device *gDevices[MAX_DEVICES];
30 const char *gDevNameList[MAX_DEVICES + 1];
31 
32 
33 static struct network_device *
34 allocate_device(driver_t *driver)
35 {
36 	char semName[64];
37 
38 	struct network_device *dev = malloc(sizeof(struct network_device));
39 	if (dev == NULL)
40 		return NULL;
41 
42 	memset(dev, 0, sizeof(struct device));
43 
44 	if (init_device(DEVNET(dev), driver) == NULL) {
45 		free(dev);
46 		return NULL;
47 	}
48 
49 	snprintf(semName, sizeof(semName), "%s rcv", gDriverName);
50 
51 	dev->receive_sem = create_sem(0, semName);
52 	if (dev->receive_sem < 0) {
53 		uninit_device(DEVNET(dev));
54 		free(dev);
55 		return NULL;
56 	}
57 
58 	dev->link_state_sem = -1;
59 
60 	ifq_init(&dev->receive_queue, semName);
61 
62 	return dev;
63 }
64 
65 
66 static void
67 free_device(struct network_device *dev)
68 {
69 	delete_sem(dev->receive_sem);
70 	ifq_uninit(&dev->receive_queue);
71 	uninit_device(DEVNET(dev));
72 	free(dev);
73 }
74 
75 
76 device_method_signature_t
77 _resolve_method(driver_t *driver, const char *name)
78 {
79 	device_method_signature_t method = NULL;
80 	int i;
81 
82 	for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
83 		if (strcmp(driver->methods[i].name, name) == 0)
84 			method = driver->methods[i].method;
85 	}
86 
87 	return method;
88 }
89 
90 
91 static status_t
92 compat_open(const char *name, uint32 flags, void **cookie)
93 {
94 	struct network_device *dev;
95 	status_t status;
96 	int i;
97 
98 	driver_printf("compat_open(%s, 0x%lx)\n", name, flags);
99 
100 	status = get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack);
101 	if (status < B_OK)
102 		return status;
103 
104 	for (i = 0; gDevNameList[i] != NULL; i++) {
105 		if (strcmp(gDevNameList[i], name) == 0)
106 			break;
107 	}
108 
109 	if (gDevNameList[i] == NULL)
110 		return B_ERROR;
111 
112 	dev = gDevices[i];
113 
114 	if (!atomic_test_and_set(&dev->open, 1, 0))
115 		return B_BUSY;
116 
117 	/* some drivers expect the softc to be zero'ed out */
118 	memset(dev->base.softc, 0, dev->base.driver->softc_size);
119 
120 	status = DEVNET(dev)->methods.attach(DEVNET(dev));
121 	if (status != 0)
122 		atomic_and(&dev->open, 0);
123 
124 	driver_printf(" ... status = 0x%ld\n", status);
125 
126 	if (status == 0) {
127 		struct ifnet *ifp = dev->ifp;
128 		struct ifreq ifr;
129 
130 		ifp->if_flags &= ~IFF_UP;
131 		ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
132 
133 		memset(&ifr, 0, sizeof(ifr));
134 		ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0);
135 		ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
136 
137 		ifp->if_flags |= IFF_UP;
138 		ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
139 	}
140 
141 	*cookie = dev;
142 	return status;
143 }
144 
145 
146 static status_t
147 compat_close(void *cookie)
148 {
149 	struct network_device *dev = cookie;
150 
151 	device_printf(DEVNET(dev), "compat_close()\n");
152 
153 	atomic_or(&DEVNET(dev)->flags, DEVICE_CLOSED);
154 
155 	/* do we need a memory barrier in read() or is the atomic_or
156 	 * (and the implicit 'lock') enough? */
157 
158 	release_sem_etc(dev->receive_sem, 1, B_RELEASE_ALL);
159 
160 	return B_OK;
161 }
162 
163 
164 static status_t
165 compat_free(void *cookie)
166 {
167 	struct network_device *dev = cookie;
168 
169 	device_printf(DEVNET(dev), "compat_free()\n");
170 
171 	DEVNET(dev)->methods.detach(DEVNET(dev));
172 
173 	/* XXX empty out the send queue */
174 
175 	atomic_and(&dev->open, 0);
176 	put_module(NET_STACK_MODULE_NAME);
177 
178 	return B_OK;
179 }
180 
181 
182 static status_t
183 compat_read(void *cookie, off_t position, void *buf, size_t *numBytes)
184 {
185 	struct network_device *dev = cookie;
186 	uint32 semFlags = B_CAN_INTERRUPT;
187 	status_t status;
188 	struct mbuf *mb;
189 	size_t len;
190 
191 	device_printf(DEVNET(dev), "compat_read(%lld, %p, [%lu])\n", position, buf,
192 		*numBytes);
193 
194 	if (DEVNET(dev)->flags & DEVICE_CLOSED)
195 		return B_INTERRUPTED;
196 
197 	if (DEVNET(dev)->flags & DEVICE_NON_BLOCK)
198 		semFlags |= B_RELATIVE_TIMEOUT;
199 
200 	do {
201 		status = acquire_sem_etc(dev->receive_sem, 1, semFlags, 0);
202 		if (DEVNET(dev)->flags & DEVICE_CLOSED)
203 			return B_INTERRUPTED;
204 
205 		if (status == B_WOULD_BLOCK) {
206 			*numBytes = 0;
207 			return B_OK;
208 		} else if (status < B_OK)
209 			return status;
210 
211 		IF_DEQUEUE(&dev->receive_queue, mb);
212 	} while (mb == NULL);
213 
214 	len = min_c(max_c((size_t)mb->m_len, 0), *numBytes);
215 
216 #if 0
217 	mb = m_defrag(mb, 0);
218 	if (mb == NULL) {
219 		*numBytes = 0;
220 		return B_NO_MEMORY;
221 	}
222 #endif
223 
224 	memcpy(buf, mtod(mb, const void *), len);
225 	*numBytes = len;
226 
227 	m_freem(mb);
228 	return B_OK;
229 }
230 
231 
232 static status_t
233 compat_write(void *cookie, off_t position, const void *buffer,
234 	size_t *numBytes)
235 {
236 	struct network_device *dev = cookie;
237 	struct mbuf *mb;
238 
239 	device_printf(DEVNET(dev), "compat_write(%lld, %p, [%lu])\n", position,
240 		buffer, *numBytes);
241 
242 	mb = m_getcl(0, MT_DATA, 0);
243 	if (mb == NULL)
244 		return ENOBUFS;
245 
246 	/* if we waited, check after if the ifp is still valid */
247 
248 	mb->m_len = min_c(*numBytes, (size_t)MCLBYTES);
249 	memcpy(mtod(mb, void *), buffer, mb->m_len);
250 
251 	return dev->ifp->if_output(dev->ifp, mb, NULL, NULL);
252 }
253 
254 
255 static status_t
256 compat_control(void *cookie, uint32 op, void *arg, size_t len)
257 {
258 	struct network_device *dev = cookie;
259 	struct ifnet *ifp = dev->ifp;
260 
261 	switch (op) {
262 		case ETHER_INIT:
263 			return B_OK;
264 
265 		case ETHER_GETADDR:
266 			return user_memcpy(arg, IF_LLADDR(dev->ifp), ETHER_ADDR_LEN);
267 
268 		case ETHER_NONBLOCK:
269 		{
270 			int32 value;
271 			if (len < 4)
272 				return B_BAD_VALUE;
273 			if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
274 				return B_BAD_ADDRESS;
275 			if (value)
276 				DEVNET(dev)->flags |= DEVICE_NON_BLOCK;
277 			else
278 				DEVNET(dev)->flags &= ~DEVICE_NON_BLOCK;
279 			return B_OK;
280 		}
281 
282 		case ETHER_SETPROMISC:
283 		{
284 			int32 value;
285 			if (len < 4)
286 				return B_BAD_VALUE;
287 			if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
288 				return B_BAD_ADDRESS;
289 			if (value)
290 				ifp->if_flags |= IFF_PROMISC;
291 			else
292 				ifp->if_flags &= ~IFF_PROMISC;
293 			return ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
294 		}
295 
296 		case ETHER_GETFRAMESIZE:
297 		{
298 			uint32 frame_size;
299 			if (len < 4)
300 				return B_BAD_VALUE;
301 			frame_size = dev->ifp->if_mtu + ETHER_HDR_LEN;
302 			return user_memcpy(arg, &frame_size, 4);
303 		}
304 
305 		case ETHER_ADDMULTI:
306 		case ETHER_REMMULTI:
307 		{
308 			struct sockaddr_dl address;
309 
310 			if (!(ifp->if_flags & IFF_MULTICAST) == 0)
311 				return EOPNOTSUPP;
312 
313 			memset(&address, 0, sizeof(address));
314 			address.sdl_family = AF_LINK;
315 			memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
316 
317 			if (op == ETHER_ADDMULTI)
318 				return if_addmulti(ifp, (struct sockaddr *)&address, NULL);
319 			else
320 				return if_delmulti(ifp, (struct sockaddr *)&address);
321 		}
322 
323 		case ETHER_GET_LINK_STATE:
324 		{
325 			struct ifmediareq mediareq;
326 			ether_link_state_t state;
327 			status_t status;
328 
329 			if (len < sizeof(ether_link_state_t))
330 				return EINVAL;
331 
332 			memset(&mediareq, 0, sizeof(mediareq));
333 			status = ifp->if_ioctl(ifp, SIOCGIFMEDIA, (caddr_t)&mediareq);
334 			if (status < B_OK)
335 				return status;
336 
337 			state.media = mediareq.ifm_active;
338 			if (mediareq.ifm_status & IFM_ACTIVE)
339 				state.media |= IFM_ACTIVE;
340 			if (mediareq.ifm_active & IFM_10_T)
341 				state.speed = 10000;
342 			else if (mediareq.ifm_active & IFM_100_TX)
343 				state.speed = 100000;
344 			else
345 				state.speed = 1000000;
346 			state.quality = 1000;
347 
348 			return user_memcpy(arg, &state, sizeof(ether_link_state_t));
349 		}
350 
351 		case ETHER_SET_LINK_STATE_SEM:
352 			if (user_memcpy(&dev->link_state_sem, arg, sizeof(sem_id)) < B_OK) {
353 				dev->link_state_sem = -1;
354 				return B_BAD_ADDRESS;
355 			}
356 			return B_OK;
357 	}
358 
359 	return B_BAD_VALUE;
360 }
361 
362 
363 device_hooks gDeviceHooks = {
364 	compat_open,
365 	compat_close,
366 	compat_free,
367 	compat_control,
368 	compat_read,
369 	compat_write,
370 };
371 
372 
373 status_t
374 _fbsd_init_hardware(driver_t *driver)
375 {
376 	struct network_device fakeDevice;
377 	device_probe_t *probe;
378 	int i;
379 
380 	dprintf("%s: init_hardware(%p)\n", gDriverName, driver);
381 
382 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
383 		return B_ERROR;
384 
385 	probe = (device_probe_t *)_resolve_method(driver, "device_probe");
386 	if (probe == NULL) {
387 		dprintf("%s: driver has no device_probe method.\n", gDriverName);
388 		return B_ERROR;
389 	}
390 
391 	memset(&fakeDevice, 0, sizeof(struct device));
392 
393 	for (i = 0; gPci->get_nth_pci_info(i, &fakeDevice.pci_info) == B_OK; i++) {
394 		int result;
395 		result = probe(DEVNET(&fakeDevice));
396 		if (result >= 0) {
397 			dprintf("%s, found %s at %d\n", gDriverName,
398 				device_get_desc(DEVNET(&fakeDevice)), i);
399 			if (DEVNET(&fakeDevice)->flags & DEVICE_DESC_ALLOCED)
400 				free((char *)DEVNET(&fakeDevice)->description);
401 			put_module(B_PCI_MODULE_NAME);
402 			return B_OK;
403 		}
404 	}
405 
406 	dprintf("%s: no hardware found.\n", gDriverName);
407 	put_module(B_PCI_MODULE_NAME);
408 
409 	return B_ERROR;
410 }
411 
412 
413 status_t
414 _fbsd_init_driver(driver_t *driver)
415 {
416 	int i, ncards = 0;
417 	status_t status;
418 	struct network_device *dev;
419 
420 	dprintf("%s: init_driver(%p)\n", gDriverName, driver);
421 
422 	status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
423 	if (status < B_OK) {
424 		driver_printf("Failed to load PCI module.\n");
425 		return status;
426 	}
427 
428 	dev = allocate_device(driver);
429 	if (dev == NULL)
430 		goto err_1;
431 
432 	status = init_compat_layer();
433 	if (status < B_OK)
434 		goto err_2;
435 
436 	status = init_mutexes();
437 	if (status < B_OK)
438 		goto err_3;
439 
440 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
441 		status = init_taskqueues();
442 		if (status < B_OK)
443 			goto err_4;
444 	}
445 
446 	status = init_mbufs();
447 	if (status < B_OK)
448 		goto err_5;
449 
450 	init_bounce_pages();
451 
452 	for (i = 0; dev != NULL
453 			&& gPci->get_nth_pci_info(i, &dev->pci_info) == B_OK; i++) {
454 		device_t base = DEVNET(dev);
455 
456 		if (base->methods.probe(base) >= 0) {
457 			device_sprintf_name(base, "net/%s/%i", gDriverName, ncards);
458 			dprintf("%s, adding %s @%d -> /dev/%s\n", gDriverName,
459 				device_get_desc(base), i, device_get_name(base));
460 
461 			gDevices[ncards] = dev;
462 			gDevNameList[ncards] = device_get_name(base);
463 
464 			ncards++;
465 			if (ncards < MAX_DEVICES)
466 				dev = allocate_device(driver);
467 			else
468 				dev = NULL;
469 		}
470 	}
471 
472 	if (dev != NULL)
473 		free_device(dev);
474 
475 	dprintf("%s, ... %d cards.\n", gDriverName, ncards);
476 
477 	gDevNameList[ncards + 1] = NULL;
478 
479 	return B_OK;
480 
481 err_5:
482 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
483 		uninit_taskqueues();
484 err_4:
485 	uninit_mutexes();
486 err_3:
487 err_2:
488 	free(dev);
489 err_1:
490 	put_module(B_PCI_MODULE_NAME);
491 	return status;
492 }
493 
494 
495 void
496 _fbsd_uninit_driver(driver_t *driver)
497 {
498 	int i;
499 
500 	dprintf("%s: uninit_driver(%p)\n", gDriverName, driver);
501 
502 	for (i = 0; gDevNameList[i] != NULL; i++) {
503 		free_device(gDevices[i]);
504 	}
505 
506 	uninit_bounce_pages();
507 	uninit_mbufs();
508 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
509 		uninit_taskqueues();
510 	uninit_mutexes();
511 
512 	put_module(B_PCI_MODULE_NAME);
513 }
514