* 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:
parent
3458a335ab
commit
9206bb3779
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user