nic session: link-state change handling

A Nic::Session client can install a signal handler that is used to
propagate changes of the link-state by calling 'link_state_sigh()'.
The actual link state is queried via 'link_state()'.

The nic-driver interface now provides a Driver_notification callback,
which is used to forward link-state changes from the driver to the
Nic::Session_component.

The following drivers now provide real link state: dde_ipxe, nic_bridge,
and usb_drv. Currently, OpenVPN, Linux nic_drv, and lan9118 do not
support link state and always report link up.

Fixes #1327
This commit is contained in:
Josef Söntgen
2015-03-11 11:33:03 +01:00
committed by Christian Helmuth
parent e4f6fca355
commit dd47129bef
21 changed files with 314 additions and 67 deletions

View File

@ -80,6 +80,11 @@ namespace Nic {
*/
virtual Mac_address mac_address() = 0;
/**
* Return current link-state (true if link detected)
*/
virtual bool link_state() = 0;
/**
* Set session belonging to this driver
*/
@ -130,6 +135,8 @@ namespace Nic {
bool _tx_alloc; /* get next packet from client or use _tx_packet */
Packet_descriptor _tx_packet; /* saved packet in case of driver errors */
Signal_context_capability _link_state_sigh;
void _send_packet_avail_signal() {
Signal_transmitter(_tx.sigh_packet_avail()).submit(); }
@ -256,8 +263,23 @@ namespace Nic {
_tx_alloc(true)
{ _device->session(this); }
/**
* Link state changed (called from driver)
*/
void link_state_changed()
{
if (_link_state_sigh.valid())
Genode::Signal_transmitter(_link_state_sigh).submit();
}
Mac_address mac_address() { return _device->mac_address(); }
bool link_state() override {
return _device->link_state(); }
void link_state_sigh(Genode::Signal_context_capability sigh) {
_link_state_sigh = sigh; }
/**
* Send packet to client (called form driver)
*/

View File

@ -144,6 +144,7 @@ class Nic_device : public Nic::Device
struct net_device *_ndev; /* Linux-net device */
fixup_t _tx_fixup;
bool const _burst;
bool _has_link { false };
public:
@ -177,11 +178,29 @@ class Nic_device : public Nic::Device
static Nic_device *add(struct net_device *ndev) {
return new (Genode::env()->heap()) Nic_device(ndev); }
/**
* Report link state
*/
void link_state(bool link)
{
/* only report changes of the link state */
if (link == _has_link)
return;
_has_link = link;
if (_session)
_session->link_state_changed();
}
/**********************
** Device interface **
**********************/
bool link_state() override { return _has_link; }
/**
* Submit packet to driver
*/
@ -344,12 +363,16 @@ int netif_carrier_ok(const struct net_device *dev)
void netif_carrier_on(struct net_device *dev)
{
dev->state &= ~(1 << __LINK_STATE_NOCARRIER);
if (_nic)
_nic->link_state(true);
}
void netif_carrier_off(struct net_device *dev)
{
dev->state |= 1 << __LINK_STATE_NOCARRIER;
if (_nic)
_nic->link_state(false);
}
#ifdef GENODE_NET_STAT