* Changed ETHER_GET_LINK_STATE ethernet driver interface, added ETHER_SET_LINK_STATE_SEM.

* The device interface list now uses class DoublyLinkedList instead of struct list.
* Implemented SIOC[SG]IFMEDIA for setting (not supported by any device yet), and
  retrieving the device media information.
* Fixed a locking bug in list_domain_interfaces().
* Added new stack function device_link_changed() that should be called in case the
  link state (media) changed.
* The ethernet device module now spawns a thread and will periodically check the media
  state of all ethernet devices that support this (if any).
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20546 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-04-04 09:41:04 +00:00
parent 3458a335ab
commit 9206bb3779
14 changed files with 330 additions and 100 deletions

View File

@ -21,21 +21,23 @@ enum {
ETHER_REMMULTI, /* remove multicast address */
ETHER_SETPROMISC, /* set promiscuous mode (int *) */
ETHER_GETFRAMESIZE, /* get frame size (required) (int *) */
ETHER_GETLINKSTATE
ETHER_SET_LINK_STATE_SEM,
/* pass over a semaphore to release on link state changes (sem_id *) */
ETHER_GET_LINK_STATE
/* get line speed, quality, duplex mode, etc. (ether_link_state_t *) */
};
/* ETHER_GETADDR - MAC address */
typedef struct {
uint8 ebyte[6];
typedef struct ether_address {
uint8 ebyte[6];
} ether_address_t;
/* ETHER_GETLINKSTATE */
typedef struct ether_link_state {
uint32 link_media; /* as specified in net/if_media.h */
uint32 link_quality; /* in one tenth of a percent */
uint64 link_speed; /* in Kbit/s */
uint32 media; /* as specified in net/if_media.h */
uint32 quality; /* in one tenth of a percent */
uint64 speed; /* in Kbit/s */
} ether_link_state_t;
#endif /* _ETHER_DRIVER_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef NET_DEVICE_H
@ -25,6 +25,8 @@ struct net_device {
uint32 type; // IFT_ETHER, ...
size_t mtu;
uint32 media;
uint64 link_speed;
uint32 link_quality;
size_t header_length;
struct net_hardware_address address;
@ -44,8 +46,10 @@ struct net_device_module_info {
status_t (*control)(struct net_device *device, int32 op,
void *argument, size_t length);
status_t (*send_data)(struct net_device *device, struct net_buffer *buffer);
status_t (*receive_data)(struct net_device *device, struct net_buffer **_buffer);
status_t (*send_data)(struct net_device *device,
struct net_buffer *buffer);
status_t (*receive_data)(struct net_device *device,
struct net_buffer **_buffer);
status_t (*set_mtu)(struct net_device *device, size_t mtu);
status_t (*set_promiscuous)(struct net_device *device, bool promiscuous);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef NET_STACK_H
@ -72,6 +72,7 @@ struct net_stack_module_info {
status_t (*unregister_device_monitor)(struct net_device *device,
net_receive_func receiveFunc, void *cookie);
status_t (*device_link_changed)(struct net_device *device);
status_t (*device_removed)(struct net_device *device);
// Utility Functions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Nathan Whitehorn.
* Copyright 2006-2007, Nathan Whitehorn.
* Distributed under the terms of the GPL License.
*/
@ -237,40 +237,45 @@ b44_ioctl(void *cookie,uint32 op,void *data,size_t len)
case ETHER_REMMULTI:
return (b44_LM_MulticastDel(&pUmDevice->lm_dev,(PLM_UINT8)(data)) == LM_STATUS_SUCCESS) ? B_OK : B_ERROR;
case ETHER_SETPROMISC:
if (*((uint8 *)(data)))
if (*((uint8 *)(data))) {
b44_LM_SetReceiveMask(&pUmDevice->lm_dev,
pUmDevice->lm_dev.ReceiveMask | LM_PROMISCUOUS_MODE);
else
} else {
b44_LM_SetReceiveMask(&pUmDevice->lm_dev,
pUmDevice->lm_dev.ReceiveMask & ~LM_PROMISCUOUS_MODE);
}
return B_OK;
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
case ETHER_GETLINKSTATE: {
case ETHER_GETLINKSTATE:
{
ether_link_state_t *state_buffer = (ether_link_state_t *)(data);
state_buffer->link_speed = (pUmDevice->lm_dev.LineSpeed == LM_LINE_SPEED_10MBPS) ? 10 : 100;
state_buffer->link_quality = (pUmDevice->lm_dev.LinkStatus == LM_STATUS_LINK_DOWN) ? 0.0 : 1.0;
state_buffer->duplex_mode = (pUmDevice->lm_dev.DuplexMode == LM_DUPLEX_MODE_FULL);
} return B_OK;
return B_OK;
}
#else
case ETHER_GETLINKSTATE:
case ETHER_GET_LINK_STATE:
{
ether_link_state_t state;
state.link_media = (pUmDevice->lm_dev.LinkStatus == LM_STATUS_LINK_DOWN) ? IFM_ACTIVE : 0;
state.media = (pUmDevice->lm_dev.LinkStatus
== LM_STATUS_LINK_DOWN) ? IFM_ACTIVE : 0;
switch (pUmDevice->lm_dev.LineSpeed) {
case LM_LINE_SPEED_10MBPS:
state.link_media |= IFM_10_T;
state.link_speed = 10000;
state.media |= IFM_10_T;
state.speed = 10000;
break;
case LM_LINE_SPEED_100MBPS:
state.link_media |= IFM_100_TX;
state.link_speed = 100000;
state.media |= IFM_100_TX;
state.speed = 100000;
break;
default:
state.link_speed = 0;
state.speed = 0;
}
state.link_media |= (pUmDevice->lm_dev.DuplexMode == LM_DUPLEX_MODE_FULL ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
state.link_quality = 1000;
state.media |= (pUmDevice->lm_dev.DuplexMode
== LM_DUPLEX_MODE_FULL ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
state.quality = 1000;
return user_memcpy(data, &state, sizeof(ether_link_state_t));
}
#endif

View File

@ -482,7 +482,8 @@ b57_ioctl(void *cookie,uint32 op,void *data,size_t len)
}
return B_OK;
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
case ETHER_GETLINKSTATE: {
case ETHER_GETLINKSTATE:
{
ether_link_state_t *state_buffer = (ether_link_state_t *)(data);
state_buffer->link_speed = pUmDevice->lm_dev.LineSpeed;
state_buffer->link_quality = (pUmDevice->lm_dev.LinkStatus == LM_STATUS_LINK_DOWN) ? 0.0 : 1.0;
@ -490,28 +491,30 @@ b57_ioctl(void *cookie,uint32 op,void *data,size_t len)
return B_OK;
}
#else
case ETHER_GETLINKSTATE:
case ETHER_GET_LINK_STATE:
{
ether_link_state_t state;
state.link_media = (pUmDevice->lm_dev.LinkStatus == LM_STATUS_LINK_DOWN) ? IFM_ACTIVE : 0;
state.media = (pUmDevice->lm_dev.LinkStatus
== LM_STATUS_LINK_DOWN) ? IFM_ACTIVE : 0;
switch (pUmDevice->lm_dev.LineSpeed) {
case LM_LINE_SPEED_10MBPS:
state.link_media |= IFM_10_T;
state.link_speed = 10000;
state.media |= IFM_10_T;
state.speed = 10000;
break;
case LM_LINE_SPEED_100MBPS:
state.link_media |= IFM_100_TX;
state.link_speed = 100000;
state.media |= IFM_100_TX;
state.speed = 100000;
break;
case LM_LINE_SPEED_1000MBPS:
state.link_media |= IFM_1000_T;
state.link_speed = 1000000;
state.media |= IFM_1000_T;
state.speed = 1000000;
break;
default:
state.link_speed = 0;
state.speed = 0;
}
state.link_media |= (pUmDevice->lm_dev.DuplexMode == LM_DUPLEX_MODE_FULL ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
state.link_quality = 1000;
state.media |= (pUmDevice->lm_dev.DuplexMode
== LM_DUPLEX_MODE_FULL ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
state.quality = 1000;
return user_memcpy(data, &state, sizeof(ether_link_state_t));
}

View File

@ -339,15 +339,15 @@ ipro1000_control(void *cookie, uint32 op, void *arg, size_t len)
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#if 0
case ETHER_GETLINKSTATE:
case ETHER_GET_LINK_STATE:
{
ether_link_state_t state;
state.link_media = (info->link ? IFM_ACTIVE : 0)
state.media = (info->link ? IFM_ACTIVE : 0)
| (info->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX)
| (info->speed == LINK_SPEED_100_MBIT ? IFM_100_TX : IFM_10_T);
state.link_speed = info->speed == LINK_SPEED_100_MBIT
state.speed = info->speed == LINK_SPEED_100_MBIT
? 100000 : 10000;
state.link_quality = 1000;
state.quality = 1000;
return user_memcpy(buffer, &state, sizeof(ether_link_state_t));
}

View File

@ -387,15 +387,15 @@ device_ioctl(void *data, uint32 msg, void *buffer, size_t bufferLength)
break;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
case ETHER_GETLINKSTATE:
case ETHER_GET_LINK_STATE:
{
ether_link_state_t state;
state.link_media = (info->link ? IFM_ACTIVE : 0)
state.media = (info->link ? IFM_ACTIVE : 0)
| (info->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX)
| (info->speed == LINK_SPEED_100_MBIT ? IFM_100_TX : IFM_10_T);
state.link_speed = info->speed == LINK_SPEED_100_MBIT
state.speed = info->speed == LINK_SPEED_100_MBIT
? 100000 : 10000;
state.link_quality = 1000;
state.quality = 1000;
return user_memcpy(buffer, &state, sizeof(ether_link_state_t));
}

View File

@ -7,10 +7,16 @@
*/
#include <ether_driver.h>
#include <ethernet.h>
#include <ether_driver.h>
#include <net_buffer.h>
#include <net_device.h>
#include <net_stack.h>
#include <lock.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <KernelExport.h>
@ -24,12 +30,76 @@
#include <string.h>
struct ethernet_device : net_device {
struct ethernet_device : DoublyLinkedListLinkImpl<ethernet_device>, net_device {
int fd;
uint32 frame_size;
};
struct net_buffer_module_info *gBufferModule;
static const bigtime_t kLinkCheckInterval = 1000000;
// 1 second
net_buffer_module_info *gBufferModule;
static net_stack_module_info *sStackModule;
static benaphore sListLock;
static DoublyLinkedList<ethernet_device> sCheckList;
static sem_id sLinkChangeSemaphore;
static thread_id sLinkCheckerThread;
static status_t
update_link_state(ethernet_device *device, bool notify = true)
{
ether_link_state state;
if (ioctl(device->fd, ETHER_GET_LINK_STATE, &state,
sizeof(ether_link_state)) < 0) {
// This device does not support retrieving the link
return EOPNOTSUPP;
}
if (device->media != state.media
|| device->link_quality != state.quality
|| device->link_speed != state.speed) {
device->media = state.media;
device->link_quality = state.quality;
device->link_speed = state.speed;
if (notify)
sStackModule->device_link_changed(device);
}
return B_OK;
}
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;
BenaphoreLocker _(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;
}
// #pragma mark -
status_t
@ -93,6 +163,27 @@ ethernet_up(net_device *_device)
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 *));
BenaphoreLocker _(&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;
@ -108,6 +199,14 @@ void
ethernet_down(net_device *_device)
{
ethernet_device *device = (ethernet_device *)_device;
BenaphoreLocker _(sListLock);
// if the device is still part of the list, remove it
if (device->GetDoublyLinkedListLink()->next != NULL
|| device->GetDoublyLinkedListLink()->previous != NULL)
sCheckList.Remove(device);
close(device->fd);
}
@ -262,6 +361,7 @@ status_t
ethernet_get_multicast_addrs(struct net_device *device,
net_hardware_address **addressArray, uint32 count)
{
// TODO: see etherpci driver for details
return EOPNOTSUPP;
}
@ -270,6 +370,7 @@ status_t
ethernet_set_multicast_addrs(struct net_device *device,
const net_hardware_address **addressArray, uint32 count)
{
// TODO: see etherpci driver for details
return EOPNOTSUPP;
}
@ -279,8 +380,44 @@ ethernet_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
{
status_t status = get_module(NET_STACK_MODULE_NAME,
(module_info **)&sStackModule);
if (status < B_OK)
return status;
new (&sCheckList) DoublyLinkedList<ethernet_device>;
// static C++ objects are not initialized in the module startup
sLinkCheckerThread = -1;
sLinkChangeSemaphore = create_sem(0, "ethernet link change");
if (sLinkChangeSemaphore < B_OK) {
put_module(NET_STACK_MODULE_NAME);
return sLinkChangeSemaphore;
}
status = benaphore_init(&sListLock, "ethernet devices");
if (status < B_OK) {
put_module(NET_STACK_MODULE_NAME);
delete_sem(sLinkChangeSemaphore);
return status;
}
return B_OK;
}
case B_MODULE_UNINIT:
{
delete_sem(sLinkChangeSemaphore);
status_t status;
wait_for_thread(sLinkCheckerThread, &status);
benaphore_destroy(&sListLock);
put_module(NET_STACK_MODULE_NAME);
return B_OK;
}
default:
return B_ERROR;

View File

@ -18,6 +18,7 @@
#include <util/AutoLock.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/route.h>
#include <sys/sockio.h>
@ -54,7 +55,8 @@ device_reader_thread(void *_interface)
// feed device monitors
// TODO: locking!
DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator();
DeviceMonitorList::Iterator iterator
= interface->monitor_funcs.GetIterator();
while (iterator.HasNext()) {
net_device_monitor *monitor = iterator.Next();
monitor->func(monitor->cookie, buffer);
@ -64,7 +66,8 @@ device_reader_thread(void *_interface)
if (type >= 0) {
// find handler for this packet
// TODO: locking!
DeviceHandlerList::Iterator iterator = interface->receive_funcs.GetIterator();
DeviceHandlerList::Iterator iterator
= interface->receive_funcs.GetIterator();
status = B_ERROR;
while (iterator.HasNext()) {
@ -135,7 +138,8 @@ remove_default_routes(net_interface_private *interface, int32 option)
route.gateway = NULL;
route.interface = interface;
if (interface->mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) {
if (interface->mask != NULL
&& (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) {
route.mask = interface->mask;
route.flags = 0;
remove_route(interface->domain, &route);
@ -157,7 +161,8 @@ add_default_routes(net_interface_private *interface, int32 option)
route.gateway = NULL;
route.interface = interface;
if (interface->mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) {
if (interface->mask != NULL
&& (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) {
route.mask = interface->mask;
route.flags = 0;
add_route(interface->domain, &route);
@ -324,16 +329,22 @@ datalink_control(net_domain *_domain, int32 option, void *value,
if (interface != NULL) {
// filter out bringing the interface up or down
if (option == SIOCSIFFLAGS
&& ((uint32)request.ifr_flags & IFF_UP) != (interface->flags & IFF_UP)) {
&& ((uint32)request.ifr_flags & IFF_UP)
!= (interface->flags & IFF_UP)) {
if ((interface->flags & IFF_UP) != 0) {
// bring the interface down
interface->flags &= ~IFF_UP;
interface->first_info->interface_down(interface->first_protocol);
interface->flags &= ~(IFF_UP | IFF_LINK);
interface->first_info->interface_down(
interface->first_protocol);
} else {
// bring it up
status = interface->first_info->interface_up(interface->first_protocol);
if (status == B_OK)
interface->flags |= IFF_UP;
status = interface->first_info->interface_up(
interface->first_protocol);
if (status == B_OK) {
interface->flags |= IFF_UP
| (interface->device->media & IFM_ACTIVE
? IFF_LINK : 0);
}
}
request.ifr_flags = interface->flags;
@ -341,8 +352,8 @@ datalink_control(net_domain *_domain, int32 option, void *value,
if (status == B_OK) {
// pass the request into the datalink protocol stack
status = interface->first_info->control(interface->first_protocol,
option, value, *_length);
status = interface->first_info->control(
interface->first_protocol, option, value, *_length);
}
} else
status = B_BAD_VALUE;
@ -704,13 +715,34 @@ interface_protocol_control(net_datalink_protocol *_protocol,
return B_BAD_ADDRESS;
// check for valid bounds
if (request.ifr_mtu < 100 || (uint32)request.ifr_mtu > interface->device->mtu)
if (request.ifr_mtu < 100
|| (uint32)request.ifr_mtu > interface->device->mtu)
return B_BAD_VALUE;
interface->mtu = request.ifr_mtu;
return B_OK;
}
case SIOCSIFMEDIA:
{
// set media
struct ifreq request;
if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK)
return B_BAD_ADDRESS;
return interface->device_interface->module->set_media(
interface->device, request.ifr_media);
}
case SIOCGIFMEDIA:
{
// get media
struct ifreq request;
request.ifr_media = interface->device->media;
return user_memcpy(&((struct ifreq *)argument)->ifr_media,
&request.ifr_media, sizeof(request.ifr_media));
}
case SIOCGIFMETRIC:
{
// get metric

View File

@ -11,11 +11,14 @@
#include "interfaces.h"
#include "utility.h"
#include <KernelExport.h>
#include <net_device.h>
#include <lock.h>
#include <util/AutoLock.h>
#include <KernelExport.h>
#include <net/if_media.h>
#include <new>
#include <string.h>
@ -112,6 +115,8 @@ list_domain_interfaces(void *_buffer, size_t *bufferSize)
if (domain == NULL)
break;
BenaphoreLocker locker(domain->lock);
net_interface *interface = NULL;
while (true) {
interface = (net_interface *)list_get_next_item(&domain->interfaces,
@ -121,17 +126,18 @@ list_domain_interfaces(void *_buffer, size_t *bufferSize)
ifreq request;
strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
if (interface->address != NULL)
memcpy(&request.ifr_addr, interface->address, interface->address->sa_len);
else {
if (interface->address != NULL) {
memcpy(&request.ifr_addr, interface->address,
interface->address->sa_len);
} else {
// empty address
request.ifr_addr.sa_len = 2;
request.ifr_addr.sa_family = AF_UNSPEC;
}
if (buffer.Copy(&request, IF_NAMESIZE
+ request.ifr_addr.sa_len) == NULL)
return buffer.Status();
+ request.ifr_addr.sa_len) == NULL)
return buffer.Status();
}
}
@ -187,6 +193,38 @@ remove_interface_from_domain(net_interface *interface)
}
void
domain_interfaces_link_changed(net_device *device)
{
// TODO: notify listeners about this!
BenaphoreLocker locker(sDomainLock);
net_domain_private *domain = NULL;
while (true) {
domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
if (domain == NULL)
break;
BenaphoreLocker locker(domain->lock);
net_interface *interface = NULL;
while (true) {
interface = (net_interface *)list_get_next_item(&domain->interfaces,
interface);
if (interface == NULL)
break;
if (interface->device == device) {
// update IFF_LINK flag
interface->flags = (interface->flags & ~IFF_LINK)
| (device->media & IFM_ACTIVE ? IFF_LINK : 0);
}
}
}
}
status_t
register_domain(int family, const char *name,
struct net_protocol_module_info *module,

View File

@ -33,6 +33,7 @@ uint32 count_domain_interfaces();
status_t list_domain_interfaces(void *buffer, size_t *_bufferSize);
status_t add_interface_to_domain(net_domain *domain, struct ifreq& request);
status_t remove_interface_from_domain(net_interface *interface);
void domain_interfaces_link_changed(net_device *device);
net_domain *get_domain(int family);
status_t register_domain(int family, const char *name,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -34,7 +34,7 @@
static benaphore sInterfaceLock;
static list sInterfaces;
static DeviceInterfaceList sInterfaces;
static uint32 sInterfaceIndex;
static uint32 sDeviceIndex;
@ -42,12 +42,10 @@ static uint32 sDeviceIndex;
static net_device_interface *
find_device_interface(const char *name)
{
net_device_interface *interface = NULL;
DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator();
while (true) {
interface = (net_device_interface *)list_get_next_item(&sInterfaces, interface);
if (interface == NULL)
break;
while (iterator.HasNext()) {
net_device_interface *interface = iterator.Next();
if (!strcmp(interface->name, name))
return interface;
@ -237,15 +235,11 @@ count_device_interfaces()
{
BenaphoreLocker locker(sInterfaceLock);
net_device_interface *interface = NULL;
DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator();
uint32 count = 0;
while (true) {
interface = (net_device_interface *)list_get_next_item(&sInterfaces,
interface);
if (interface == NULL)
break;
while (iterator.HasNext()) {
iterator.Next();
count++;
}
@ -263,22 +257,19 @@ list_device_interfaces(void *_buffer, size_t *bufferSize)
{
BenaphoreLocker locker(sInterfaceLock);
DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator();
UserBuffer buffer(_buffer, *bufferSize);
net_device_interface *interface = NULL;
while (true) {
interface = (net_device_interface *)list_get_next_item(&sInterfaces,
interface);
if (interface == NULL)
break;
while (iterator.HasNext()) {
net_device_interface *interface = iterator.Next();
ifreq request;
strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
get_device_interface_address(interface, &request.ifr_addr);
if (buffer.Copy(&request, IF_NAMESIZE
+ request.ifr_addr.sa_len) == NULL)
return buffer.Status();
+ request.ifr_addr.sa_len) == NULL)
return buffer.Status();
}
*bufferSize = buffer.ConsumedAmount();
@ -300,7 +291,7 @@ put_device_interface(struct net_device_interface *interface)
{
BenaphoreLocker locker(sInterfaceLock);
list_remove_item(&sInterfaces, interface);
sInterfaces.Remove(interface);
}
interface->module->uninit_device(interface->device);
@ -315,12 +306,10 @@ struct net_device_interface *
get_device_interface(uint32 index)
{
BenaphoreLocker locker(sInterfaceLock);
net_device_interface *interface = NULL;
DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator();
while (true) {
interface = (net_device_interface *)list_get_next_item(&sInterfaces, interface);
if (interface == NULL)
break;
while (iterator.HasNext()) {
net_device_interface *interface = iterator.Next();
if (interface->device->index == index) {
if (atomic_add(&interface->ref_count, 1) != 0)
@ -380,7 +369,7 @@ get_device_interface(const char *name)
device->index = ++sDeviceIndex;
device->module = module;
list_add_item(&sInterfaces, interface);
sInterfaces.Add(interface);
return interface;
} else
module->uninit_device(device);
@ -589,6 +578,19 @@ unregister_device_monitor(struct net_device *device,
}
/*!
This function is called by device modules in case their link
state changed, ie. if an ethernet cable was plugged in or
removed.
*/
status_t
device_link_changed(net_device *device)
{
domain_interfaces_link_changed(device);
return B_OK;
}
/*!
This function is called by device modules once their device got
physically removed, ie. a USB networking card is unplugged.
@ -612,7 +614,8 @@ init_interfaces()
if (benaphore_init(&sInterfaceLock, "net interfaces") < B_OK)
return B_ERROR;
list_init(&sInterfaces);
new (&sInterfaces) DeviceInterfaceList;
// static C++ objects are not initialized in the module startup
return B_OK;
}

View File

@ -29,8 +29,8 @@ struct net_device_monitor : public DoublyLinkedListLinkImpl<net_device_monitor>
typedef DoublyLinkedList<net_device_handler> DeviceHandlerList;
typedef DoublyLinkedList<net_device_monitor> DeviceMonitorList;
struct net_device_interface {
struct list_link link;
struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
//struct list_link link;
const char *name;
struct net_device_module_info *module;
struct net_device *device;
@ -46,6 +46,8 @@ struct net_device_interface {
DeviceHandlerList receive_funcs;
};
typedef DoublyLinkedList<net_device_interface> DeviceInterfaceList;
struct net_interface_private : net_interface {
char base_name[IF_NAMESIZE];
net_device_interface *device_interface;
@ -90,6 +92,7 @@ status_t register_device_monitor(struct net_device *device,
net_receive_func receiveFunc, void *cookie);
status_t unregister_device_monitor(struct net_device *device,
net_receive_func receiveFunc, void *cookie);
status_t device_link_changed(net_device *device);
status_t device_removed(net_device *device);
#endif // INTERFACES_H

View File

@ -911,6 +911,7 @@ static net_stack_module_info sNetStackModule = {
unregister_device_handler,
register_device_monitor,
unregister_device_monitor,
device_link_changed,
device_removed,
notify_socket,