vfs: check userland buffers before reading them.
[haiku.git] / src / libs / compat / freebsd_network / compat.c
blob3b40c9f2da77cc9d5829d2c350b9897a56701bab
1 /*
2 * Copyright 2007, Hugo Santos, hugosantos@gmail.com. All Rights Reserved.
3 * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
4 * Copyright 2004, Marcus Overhagen. All Rights Reserved.
6 * Distributed under the terms of the MIT License.
7 */
10 #include "device.h"
12 #include <stdio.h>
14 #include <KernelExport.h>
15 #include <image.h>
17 #include <util/BitUtils.h>
19 #include <compat/machine/resource.h>
20 #include <compat/dev/mii/mii.h>
21 #include <compat/sys/bus.h>
22 #include <compat/sys/malloc.h>
23 #include <compat/net/if_media.h>
25 #include <compat/dev/mii/miivar.h>
27 #include "compat_cpp.h"
30 spinlock __haiku_intr_spinlock;
32 struct net_stack_module_info *gStack;
33 pci_module_info *gPci;
34 struct pci_x86_module_info *gPCIx86;
36 static struct list sRootDevices;
37 static int sNextUnit;
39 // #pragma mark - private functions
42 static device_t
43 init_device(device_t device, driver_t *driver)
45 list_init_etc(&device->children, offsetof(struct device, link));
46 device->unit = sNextUnit++;
48 if (driver != NULL && device_set_driver(device, driver) < 0)
49 return NULL;
51 return device;
55 static device_t
56 new_device(driver_t *driver)
58 device_t dev = malloc(sizeof(struct device));
59 if (dev == NULL)
60 return NULL;
62 memset(dev, 0, sizeof(struct device));
64 if (init_device(dev, driver) == NULL) {
65 free(dev);
66 return NULL;
69 return dev;
73 static image_id
74 find_own_image()
76 int32 cookie = 0;
77 image_info info;
78 while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) {
79 if (((addr_t)info.text <= (addr_t)find_own_image
80 && (addr_t)info.text + (addr_t)info.text_size
81 > (addr_t)find_own_image)) {
82 // found our own image
83 return info.id;
87 return B_ENTRY_NOT_FOUND;
91 static device_method_signature_t
92 resolve_method(driver_t *driver, const char *name)
94 device_method_signature_t method = NULL;
95 int i;
97 for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
98 if (strcmp(driver->methods[i].name, name) == 0)
99 method = driver->methods[i].method;
102 return method;
106 // #pragma mark - Device
109 void
110 driver_printf(const char *format, ...)
112 va_list vl;
113 va_start(vl, format);
114 driver_vprintf(format, vl);
115 va_end(vl);
119 static void
120 driver_vprintf_etc(const char *extra, const char *format, va_list vl)
122 char buf[256];
123 vsnprintf(buf, sizeof(buf), format, vl);
125 if (extra)
126 dprintf("[%s] (%s) %s", gDriverName, extra, buf);
127 else
128 dprintf("[%s] %s", gDriverName, buf);
132 void
133 driver_vprintf(const char *format, va_list vl)
135 driver_vprintf_etc(NULL, format, vl);
140 device_printf(device_t dev, const char *format, ...)
142 va_list vl;
144 va_start(vl, format);
145 driver_vprintf_etc(dev->device_name, format, vl);
146 va_end(vl);
147 return 0;
151 void
152 device_set_desc(device_t dev, const char *desc)
154 dev->description = desc;
158 void
159 device_set_desc_copy(device_t dev, const char *desc)
161 dev->description = strdup(desc);
162 dev->flags |= DEVICE_DESC_ALLOCED;
166 const char *
167 device_get_desc(device_t dev)
169 return dev->description;
173 device_t
174 device_get_parent(device_t dev)
176 return dev->parent;
180 devclass_t
181 device_get_devclass(device_t dev)
183 // TODO find out what to do
184 return 0;
189 device_get_children(device_t dev, device_t **devlistp, int *devcountp)
191 int count;
192 device_t child = NULL;
193 device_t *list;
195 count = 0;
196 while ((child = list_get_next_item(&dev->children, child)) != NULL) {
197 count++;
200 list = malloc(count * sizeof(device_t));
201 if (!list)
202 return (ENOMEM);
204 count = 0;
205 while ((child = list_get_next_item(&dev->children, child)) != NULL) {
206 list[count] = child;
207 count++;
210 *devlistp = list;
211 *devcountp = count;
213 return (0);
217 void
218 device_set_ivars(device_t dev, void *ivars)
220 dev->ivars = ivars;
224 void *
225 device_get_ivars(device_t dev)
227 return dev->ivars;
231 const char *
232 device_get_name(device_t dev)
234 if (dev == NULL)
235 return NULL;
237 return dev->device_name;
242 device_get_unit(device_t dev)
244 return dev->unit;
248 const char *
249 device_get_nameunit(device_t dev)
251 return dev->nameunit;
255 void *
256 device_get_softc(device_t dev)
258 return dev->softc;
262 u_int32_t
263 device_get_flags(device_t dev)
265 return dev->flags;
270 device_set_driver(device_t dev, driver_t *driver)
272 device_method_signature_t method = NULL;
273 int i;
275 dev->softc = malloc(driver->softc_size);
276 if (dev->softc == NULL)
277 return -1;
279 memset(dev->softc, 0, driver->softc_size);
280 dev->driver = driver;
282 for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
283 device_method_t *mth = &driver->methods[i];
285 if (strcmp(mth->name, "device_probe") == 0)
286 dev->methods.probe = (void *)mth->method;
287 else if (strcmp(mth->name, "device_attach") == 0)
288 dev->methods.attach = (void *)mth->method;
289 else if (strcmp(mth->name, "device_detach") == 0)
290 dev->methods.detach = (void *)mth->method;
291 else if (strcmp(mth->name, "device_suspend") == 0)
292 dev->methods.suspend = (void *)mth->method;
293 else if (strcmp(mth->name, "device_resume") == 0)
294 dev->methods.resume = (void *)mth->method;
295 else if (strcmp(mth->name, "device_shutdown") == 0)
296 dev->methods.shutdown = (void *)mth->method;
297 else if (strcmp(mth->name, "miibus_readreg") == 0)
298 dev->methods.miibus_readreg = (void *)mth->method;
299 else if (strcmp(mth->name, "miibus_writereg") == 0)
300 dev->methods.miibus_writereg = (void *)mth->method;
301 else if (strcmp(mth->name, "miibus_statchg") == 0)
302 dev->methods.miibus_statchg = (void *)mth->method;
303 else if (!strcmp(mth->name, "miibus_linkchg"))
304 dev->methods.miibus_linkchg = (void *)mth->method;
305 else if (!strcmp(mth->name, "miibus_mediainit"))
306 dev->methods.miibus_mediainit = (void *)mth->method;
309 return 0;
314 device_is_alive(device_t device)
316 return (device->flags & DEVICE_ATTACHED) != 0;
320 device_t
321 device_add_child(device_t parent, const char *name, int unit)
323 device_t child = NULL;
325 if (name != NULL) {
326 if (strcmp(name, "miibus") == 0)
327 child = new_device(&miibus_driver);
328 else {
329 // find matching driver structure
330 driver_t **driver;
331 char symbol[128];
333 snprintf(symbol, sizeof(symbol), "__fbsd_%s_%s", name,
334 parent->driver->name);
335 if (get_image_symbol(find_own_image(), symbol, B_SYMBOL_TYPE_DATA,
336 (void **)&driver) == B_OK) {
337 child = new_device(*driver);
338 } else
339 device_printf(parent, "couldn't find symbol %s\n", symbol);
341 } else
342 child = new_device(NULL);
344 if (child == NULL)
345 return NULL;
347 if (name != NULL)
348 strlcpy(child->device_name, name, sizeof(child->device_name));
350 child->parent = parent;
352 if (parent != NULL) {
353 list_add_item(&parent->children, child);
354 child->root = parent->root;
355 } else {
356 if (sRootDevices.link.next == NULL)
357 list_init_etc(&sRootDevices, offsetof(struct device, link));
358 list_add_item(&sRootDevices, child);
361 return child;
365 /*! Delete the child and all of its children. Detach as necessary.
368 device_delete_child(device_t parent, device_t child)
370 int status;
372 if (child == NULL)
373 return 0;
375 if (parent != NULL)
376 list_remove_item(&parent->children, child);
377 else
378 list_remove_item(&sRootDevices, child);
380 // We differentiate from the FreeBSD logic here - it will first delete
381 // the children, and will then detach the device.
382 // This has the problem that you cannot safely call device_delete_child()
383 // as you don't know if one of the children deletes its own children this
384 // way when it is detached.
385 // Therefore, we'll detach first, and then delete whatever is left.
387 parent = child;
388 child = NULL;
390 // detach children
391 while ((child = list_get_next_item(&parent->children, child)) != NULL) {
392 device_detach(child);
395 // detach device
396 status = device_detach(parent);
397 if (status != 0)
398 return status;
400 // delete children
401 while ((child = list_get_first_item(&parent->children)) != NULL) {
402 device_delete_child(parent, child);
405 // delete device
406 if (parent->flags & DEVICE_DESC_ALLOCED)
407 free((char *)parent->description);
409 free(parent->softc);
410 free(parent);
411 return 0;
416 device_is_attached(device_t device)
418 return (device->flags & DEVICE_ATTACHED) != 0;
423 device_attach(device_t device)
425 int result;
427 if (device->driver == NULL
428 || device->methods.attach == NULL)
429 return B_ERROR;
431 result = device->methods.attach(device);
433 if (result == 0)
434 atomic_or(&device->flags, DEVICE_ATTACHED);
436 if (result == 0)
437 result = start_wlan(device);
439 return result;
444 device_detach(device_t device)
446 if (device->driver == NULL)
447 return B_ERROR;
449 if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0
450 && device->methods.detach != NULL) {
451 int result = B_OK;
453 result = stop_wlan(device);
454 if (result != 0) {
455 atomic_or(&device->flags, DEVICE_ATTACHED);
456 return result;
459 result = device->methods.detach(device);
460 if (result != 0) {
461 atomic_or(&device->flags, DEVICE_ATTACHED);
462 return result;
466 return 0;
471 bus_generic_attach(device_t dev)
473 device_t child = NULL;
475 while ((child = list_get_next_item(&dev->children, child)) != NULL) {
476 if (child->driver == NULL) {
477 driver_t *driver = __haiku_select_miibus_driver(child);
478 if (driver == NULL) {
479 struct mii_attach_args *ma = device_get_ivars(child);
481 device_printf(dev, "No PHY module found (%x/%x)!\n",
482 MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2));
483 } else
484 device_set_driver(child, driver);
485 } else
486 child->methods.probe(child);
488 if (child->driver != NULL) {
489 int result = device_attach(child);
490 if (result != 0)
491 return result;
495 return 0;
500 bus_generic_detach(device_t device)
502 device_t child = NULL;
504 if ((device->flags & DEVICE_ATTACHED) == 0)
505 return B_ERROR;
507 while (true) {
508 child = list_get_next_item(&device->children, child);
509 if (child == NULL)
510 break;
512 device_detach(child);
515 return 0;
519 // #pragma mark - Misc, Malloc
522 device_t
523 find_root_device(int unit)
525 device_t device = NULL;
527 while ((device = list_get_next_item(&sRootDevices, device)) != NULL) {
528 if (device->unit <= unit)
529 return device;
532 return NULL;
536 driver_t *
537 __haiku_probe_miibus(device_t dev, driver_t *drivers[])
539 driver_t *selected = NULL;
540 int i, selectedResult = 0;
542 if (drivers == NULL)
543 return NULL;
545 for (i = 0; drivers[i]; i++) {
546 device_probe_t *probe = (device_probe_t *)
547 resolve_method(drivers[i], "device_probe");
548 if (probe) {
549 int result = probe(dev);
550 if (result >= 0) {
551 if (selected == NULL || result < selectedResult) {
552 selected = drivers[i];
553 selectedResult = result;
554 device_printf(dev, "Found MII: %s\n", selected->name);
560 return selected;
565 printf(const char *format, ...)
567 char buf[256];
568 va_list vl;
569 va_start(vl, format);
570 vsnprintf(buf, sizeof(buf), format, vl);
571 va_end(vl);
572 dprintf(buf);
574 return 0;
579 ffs(int value)
581 int i = 1;
583 if (value == 0)
584 return 0;
586 for (; !(value & 1); i++)
587 value >>= 1;
589 return i;
594 resource_int_value(const char *name, int unit, const char *resname,
595 int *result)
597 /* no support for hints */
598 return -1;
602 void *
603 _kernel_malloc(size_t size, int flags)
605 // our kernel malloc() is insufficient, must handle M_WAIT
607 // According to the FreeBSD kernel malloc man page the allocator is expected
608 // to return power of two aligned addresses for allocations up to one page
609 // size. While it also states that this shouldn't be relied upon, at least
610 // bus_dmamem_alloc expects it and drivers may depend on it as well.
611 void *ptr
612 = memalign(size >= PAGESIZE ? PAGESIZE : next_power_of_2(size), size);
613 if (ptr == NULL)
614 return NULL;
616 if (flags & M_ZERO)
617 memset(ptr, 0, size);
619 return ptr;
623 void
624 _kernel_free(void *ptr)
626 free(ptr);
630 void *
631 _kernel_contigmalloc(const char *file, int line, size_t size, int flags,
632 vm_paddr_t low, vm_paddr_t high, unsigned long alignment,
633 unsigned long boundary)
635 return _kernel_contigmalloc_cpp(file, line, size, low, high,
636 alignment, boundary, (flags & M_ZERO) != 0, (flags & M_NOWAIT) != 0);
640 void
641 _kernel_contigfree(void *addr, size_t size)
643 delete_area(area_for(addr));
647 vm_paddr_t
648 pmap_kextract(vm_offset_t virtualAddress)
650 physical_entry entry;
651 status_t status = get_memory_map((void *)virtualAddress, 1, &entry, 1);
652 if (status < B_OK) {
653 panic("fbsd compat: get_memory_map failed for %p, error %08" B_PRIx32
654 "\n", (void *)virtualAddress, status);
657 return (vm_paddr_t)entry.address;