static status_t ethernet_link_checker(void *) { while (true) { status_t status = acquire_sem_etc(sLinkChangeSemaphore, 1, B_RELATIVE_TIMEOUT, kLinkCheckInterval); if (status == B_BAD_SEM_ID) break; MutexLocker _(sListLock); if (sCheckList.IsEmpty()) break; // check link state of all existing devices DoublyLinkedList<ethernet_device>::Iterator iterator = sCheckList.GetIterator(); while (iterator.HasNext()) { update_link_state(iterator.Next()); } } return B_OK; }
status_t ethernet_up(net_device *_device) { ethernet_device *device = (ethernet_device *)_device; device->fd = open(device->name, O_RDWR); if (device->fd < 0) return errno; uint64 dummy; if (ioctl(device->fd, ETHER_INIT, &dummy, sizeof(dummy)) < 0) goto err; if (ioctl(device->fd, ETHER_GETADDR, device->address.data, ETHER_ADDRESS_LENGTH) < 0) goto err; if (ioctl(device->fd, ETHER_GETFRAMESIZE, &device->frame_size, sizeof(uint32)) < 0) { // this call is obviously optional device->frame_size = ETHER_MAX_FRAME_SIZE; } if (update_link_state(device, false) == B_OK) { // device supports retrieval of the link state // Set the change notification semaphore; doesn't matter // if this is supported by the device or not ioctl(device->fd, ETHER_SET_LINK_STATE_SEM, &sLinkChangeSemaphore, sizeof(sem_id)); MutexLocker _(&sListLock); if (sCheckList.IsEmpty()) { // start thread sLinkCheckerThread = spawn_kernel_thread(ethernet_link_checker, "ethernet link state checker", B_LOW_PRIORITY, NULL); if (sLinkCheckerThread >= B_OK) resume_thread(sLinkCheckerThread); } sCheckList.Add(device); } device->address.length = ETHER_ADDRESS_LENGTH; device->mtu = device->frame_size - device->header_length; return B_OK; err: close(device->fd); device->fd = -1; return errno; }