From dd47129bef8751397203a208abfc13a486000dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Wed, 11 Mar 2015 11:33:03 +0100 Subject: [PATCH] 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 --- repos/dde_ipxe/include/dde_ipxe/nic.h | 22 +++++++-- repos/dde_ipxe/src/drivers/nic/main.cc | 42 ++++++++++------ repos/dde_ipxe/src/drivers/nic_stat/main.cc | 42 ++++++++++------ repos/dde_ipxe/src/lib/dde_ipxe/nic.c | 49 ++++++++++++++++--- .../src/lib/usb/include/nic/component.h | 22 +++++++++ repos/dde_linux/src/lib/usb/nic/nic.cc | 23 +++++++++ repos/os/include/nic/component.h | 26 ++++++++-- repos/os/include/nic/driver.h | 16 +++++- repos/os/include/nic_session/client.h | 7 +++ repos/os/include/nic_session/nic_session.h | 15 +++++- repos/os/src/drivers/nic/lan9118/lan9118.h | 13 ++++- repos/os/src/drivers/nic/lan9118/main.cc | 5 +- repos/os/src/drivers/nic/linux/main.cc | 25 +++++++--- repos/os/src/server/nic_bridge/component.cc | 4 ++ repos/os/src/server/nic_bridge/component.h | 17 +++++++ repos/os/src/server/nic_bridge/nic.cc | 1 + repos/os/src/server/nic_bridge/nic.h | 1 + .../src/server/nic_bridge/packet_handler.cc | 13 ++++- .../os/src/server/nic_bridge/packet_handler.h | 6 +++ repos/os/src/server/nic_loopback/main.cc | 8 +++ repos/ports/src/app/openvpn/main.cc | 24 ++++++--- 21 files changed, 314 insertions(+), 67 deletions(-) diff --git a/repos/dde_ipxe/include/dde_ipxe/nic.h b/repos/dde_ipxe/include/dde_ipxe/nic.h index 7a7b3097cf..3ae0a57ea1 100644 --- a/repos/dde_ipxe/include/dde_ipxe/nic.h +++ b/repos/dde_ipxe/include/dde_ipxe/nic.h @@ -15,6 +15,11 @@ #ifndef _DDE_IPXE__NIC_H_ #define _DDE_IPXE__NIC_H_ +/** + * Link-state change callback + */ +typedef void (*dde_ipxe_nic_link_cb)(void); + /** * Packet reception callback * @@ -27,14 +32,14 @@ typedef void (*dde_ipxe_nic_rx_cb)(unsigned if_index, const char *packet, unsign /** * Register packet reception callback * - * \param cb new callback function - * - * \return old callback function pointer + * \param rx_cb packet-reception callback function + * \param link_cb link-state change callback function * * This registers a function pointer as rx callback. Incoming ethernet packets * are passed to this function. */ -extern dde_ipxe_nic_rx_cb dde_ipxe_nic_register_rx_callback(dde_ipxe_nic_rx_cb cb); +extern void dde_ipxe_nic_register_callbacks(dde_ipxe_nic_rx_cb rx_cb, + dde_ipxe_nic_link_cb link_cb); /** * Send packet @@ -57,6 +62,15 @@ extern int dde_ipxe_nic_tx(unsigned if_index, const char *packet, unsigned packe */ extern int dde_ipxe_nic_get_mac_addr(unsigned if_index, char *out_mac_addr); +/** + * Get current link-state of device + * + * \param if_index index of the receiving network interface + * + * \return 1 if link is up, 0 if no link is detected + */ +extern int dde_ipxe_nic_link_state(unsigned if_index); + /** * Initialize network sub-system * diff --git a/repos/dde_ipxe/src/drivers/nic/main.cc b/repos/dde_ipxe/src/drivers/nic/main.cc index 86f71438cf..b533c3882f 100644 --- a/repos/dde_ipxe/src/drivers/nic/main.cc +++ b/repos/dde_ipxe/src/drivers/nic/main.cc @@ -32,29 +32,32 @@ namespace Ipxe { static Driver *instance; - static void dde_rx_handler(unsigned if_index, - const char *packet, - unsigned packet_len) + private: + + Nic::Mac_address _mac_addr; + Nic::Rx_buffer_alloc &_alloc; + Nic::Driver_notification &_notify; + + static void _rx_callback(unsigned if_index, + const char *packet, + unsigned packet_len) { instance->rx_handler(packet, packet_len); } - private: - - Nic::Mac_address _mac_addr; - Nic::Rx_buffer_alloc &_alloc; + static void _link_callback() { instance->link_state_changed(); } public: - Driver(Nic::Rx_buffer_alloc &alloc) - : _alloc(alloc) + Driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify) + : _alloc(alloc), _notify(notify) { PINF("--- init iPXE NIC"); int cnt = dde_ipxe_nic_init(); PINF(" number of devices: %d", cnt); - PINF("--- init rx_callbacks"); - dde_ipxe_nic_register_rx_callback(dde_rx_handler); + PINF("--- init callbacks"); + dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback); dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr); PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x", @@ -70,16 +73,23 @@ namespace Ipxe { Genode::memcpy(buffer, packet, packet_len); _alloc.submit(); } catch (...) { - PDBG("failed to process received packet"); + PDBG("failed to process received packet"); } } + void link_state_changed() { _notify.link_state_changed(); } + /*************************** ** Nic::Driver interface ** ***************************/ - Nic::Mac_address mac_address() { return _mac_addr; } + Nic::Mac_address mac_address() override { return _mac_addr; } + + bool link_state() override + { + return dde_ipxe_nic_link_state(1); + } void tx(char const *packet, Genode::size_t size) { @@ -87,7 +97,6 @@ namespace Ipxe { PWRN("Sending packet failed!"); } - /****************************** ** Irq_activation interface ** ******************************/ @@ -97,9 +106,10 @@ namespace Ipxe { class Driver_factory : public Nic::Driver_factory { - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc) + Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, + Nic::Driver_notification ¬ify) { - Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc); + Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc, notify); return Driver::instance; } diff --git a/repos/dde_ipxe/src/drivers/nic_stat/main.cc b/repos/dde_ipxe/src/drivers/nic_stat/main.cc index fcedf3f2d0..a0750d7f1b 100644 --- a/repos/dde_ipxe/src/drivers/nic_stat/main.cc +++ b/repos/dde_ipxe/src/drivers/nic_stat/main.cc @@ -36,32 +36,35 @@ namespace Ipxe { static Driver *instance; - static void dde_rx_handler(unsigned if_index, - const char *packet, - unsigned packet_len) + private: + + Nic::Mac_address _mac_addr; + Nic::Rx_buffer_alloc &_alloc; + Nic::Driver_notification &_notify; + + Timer::Connection _timer; + Nic::Measurement _stat; + + static void _rx_callback(unsigned if_index, + const char *packet, + unsigned packet_len) { instance->rx_handler_stat(packet, packet_len); } - private: - - Nic::Mac_address _mac_addr; - Nic::Rx_buffer_alloc &_alloc; - - Timer::Connection _timer; - Nic::Measurement _stat; + static void _link_callback() { instance->link_state_changed(); } public: - Driver(Nic::Rx_buffer_alloc &alloc) - : _alloc(alloc), _stat(_timer) + Driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify) + : _alloc(alloc), _notify(notify), _stat(_timer) { PINF("--- init iPXE NIC"); int cnt = dde_ipxe_nic_init(); PINF(" number of devices: %d", cnt); - PINF("--- init rx_callbacks"); - dde_ipxe_nic_register_rx_callback(dde_rx_handler); + PINF("--- init callbacks"); + dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback); dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr); PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x", @@ -90,6 +93,8 @@ namespace Ipxe { _alloc.submit(); } + void link_state_changed() { _notify.link_state_changed(); } + /*************************** ** Nic::Driver interface ** @@ -97,6 +102,11 @@ namespace Ipxe { Nic::Mac_address mac_address() { return _mac_addr; } + bool link_state() override + { + return dde_ipxe_nic_link_state(1); + } + void tx(char const *packet, Genode::size_t size) { if (dde_ipxe_nic_tx(1, packet, size)) @@ -112,9 +122,9 @@ namespace Ipxe { class Driver_factory : public Nic::Driver_factory { - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc) + Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify) { - Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc); + Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc, notify); return Driver::instance; } diff --git a/repos/dde_ipxe/src/lib/dde_ipxe/nic.c b/repos/dde_ipxe/src/lib/dde_ipxe/nic.c index f9134c97ca..ef64773e8c 100644 --- a/repos/dde_ipxe/src/lib/dde_ipxe/nic.c +++ b/repos/dde_ipxe/src/lib/dde_ipxe/nic.c @@ -48,9 +48,15 @@ static struct dde_kit_sem *bh_sema; static struct net_device *net_dev; /** - * RX callback function pointer + * Link-state change detected */ -static dde_ipxe_nic_rx_cb rx_callback; +static int link_state_changed; + +/** + * Callback function pointers + */ +static dde_ipxe_nic_link_cb link_callback; +static dde_ipxe_nic_rx_cb rx_callback; /** * Known iPXE driver structures (located in the driver binaries) @@ -71,7 +77,6 @@ static struct pci_driver *pci_drivers[] = { &pcnet32_driver }; - /** * Update BARs of PCI device */ @@ -201,9 +206,15 @@ static void irq_handler(void *p) { ENTER; + /* check for the link-state to change on each interrupt */ + int link_ok = netdev_link_ok(net_dev); + + /* poll the device for packets and also link-state changes */ netdev_poll(net_dev); dde_kit_sem_up(bh_sema); + link_state_changed = (link_ok != netdev_link_ok(net_dev)); + LEAVE; } @@ -220,6 +231,15 @@ static void bh_handler(void *p) ENTER; + /* report link-state changes */ + if (link_state_changed) { + LEAVE; + if (link_callback) + link_callback(); + ENTER; + link_state_changed = 0; + } + struct io_buffer *iobuf; while ((iobuf = netdev_rx_dequeue(net_dev))) { LEAVE; @@ -238,15 +258,30 @@ static void bh_handler(void *p) ** API implementation ** ************************/ -dde_ipxe_nic_rx_cb dde_ipxe_nic_register_rx_callback(dde_ipxe_nic_rx_cb cb) +void dde_ipxe_nic_register_callbacks(dde_ipxe_nic_rx_cb rx_cb, + dde_ipxe_nic_link_cb link_cb) { ENTER; - dde_ipxe_nic_rx_cb old = rx_callback; - rx_callback = cb; + rx_callback = rx_cb; + link_callback = link_cb; LEAVE; - return old; +} + + +int dde_ipxe_nic_link_state(unsigned if_index) +{ + if (if_index != 1) + return -1; + + ENTER; + + int link_state = netdev_link_ok(net_dev); + + LEAVE; + + return link_state; } diff --git a/repos/dde_linux/src/lib/usb/include/nic/component.h b/repos/dde_linux/src/lib/usb/include/nic/component.h index 0cd8c3e092..5fc61f668c 100644 --- a/repos/dde_linux/src/lib/usb/include/nic/component.h +++ b/repos/dde_linux/src/lib/usb/include/nic/component.h @@ -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) */ diff --git a/repos/dde_linux/src/lib/usb/nic/nic.cc b/repos/dde_linux/src/lib/usb/nic/nic.cc index 5fd7cc3d1f..a39548e733 100644 --- a/repos/dde_linux/src/lib/usb/nic/nic.cc +++ b/repos/dde_linux/src/lib/usb/nic/nic.cc @@ -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 diff --git a/repos/os/include/nic/component.h b/repos/os/include/nic/component.h index b70a770cd7..d679985aa8 100644 --- a/repos/os/include/nic/component.h +++ b/repos/os/include/nic/component.h @@ -39,13 +39,16 @@ namespace Nic { class Nic::Session_component : public Genode::Allocator_avl, - public Session_rpc_object, public Rx_buffer_alloc + public Session_rpc_object, public Rx_buffer_alloc, + public Driver_notification { private: Driver_factory &_driver_factory; Driver &_driver; + Genode::Signal_context_capability _link_state_sigh; + /* rx packet descriptor */ Genode::Packet_descriptor _curr_rx_packet; @@ -126,7 +129,7 @@ class Nic::Session_component : public Genode::Allocator_avl, Genode::env()->ram_session()->alloc(rx_buf_size), static_cast(this), ep), _driver_factory(driver_factory), - _driver(*driver_factory.create(*this)), + _driver(*driver_factory.create(*this, *this)), _tx_thread(_tx.sink(), _driver) { } @@ -138,12 +141,21 @@ class Nic::Session_component : public Genode::Allocator_avl, _driver_factory.destroy(&_driver); } + /*********************************** + ** Driver-notification interface ** + ***********************************/ + + void link_state_changed() override + { + if (_link_state_sigh.valid()) + Genode::Signal_transmitter(_link_state_sigh).submit(); + } /******************************* ** Rx_buffer_alloc interface ** *******************************/ - void *alloc(Genode::size_t size) + void *alloc(Genode::size_t size) override { /* assign rx packet descriptor */ _curr_rx_packet = _rx.source()->alloc_packet(size); @@ -151,7 +163,7 @@ class Nic::Session_component : public Genode::Allocator_avl, return _rx.source()->packet_content(_curr_rx_packet); } - void submit() + void submit() override { /* check for acknowledgements from the client */ while (_rx.source()->ack_avail()) { @@ -175,8 +187,14 @@ class Nic::Session_component : public Genode::Allocator_avl, ****************************/ Mac_address mac_address() { return _driver.mac_address(); } + bool link_state() { return _driver.link_state(); } Tx::Sink* tx_sink() { return _tx.sink(); } Rx::Source* rx_source() { return _rx.source(); } + + void link_state_sigh(Genode::Signal_context_capability sigh) override + { + _link_state_sigh = sigh; + } }; diff --git a/repos/os/include/nic/driver.h b/repos/os/include/nic/driver.h index 1960a283a7..c1d9878032 100644 --- a/repos/os/include/nic/driver.h +++ b/repos/os/include/nic/driver.h @@ -22,6 +22,7 @@ namespace Nic { struct Rx_buffer_alloc; struct Driver; struct Driver_factory; + struct Driver_notification; } @@ -42,6 +43,12 @@ struct Nic::Rx_buffer_alloc }; +/** + * Interface for driver-to-component notifications + */ +struct Nic::Driver_notification { virtual void link_state_changed() = 0; }; + + /** * Interface to be implemented by the device-specific driver code */ @@ -52,6 +59,11 @@ struct Nic::Driver : Genode::Irq_handler */ virtual Mac_address mac_address() = 0; + /** + * Return link state (true if link detected) + */ + virtual bool link_state() = 0; + /** * Transmit packet * @@ -83,8 +95,10 @@ struct Nic::Driver_factory * * \param rx_buffer_alloc buffer allocator used for storing incoming * packets + * \param notifier callback for notifications */ - virtual Driver *create(Rx_buffer_alloc &rx_buffer_alloc) = 0; + virtual Driver *create(Rx_buffer_alloc &rx_buffer_alloc, + Driver_notification ¬ify) = 0; /** * Destroy driver diff --git a/repos/os/include/nic_session/client.h b/repos/os/include/nic_session/client.h index 718f945b70..74701a424c 100644 --- a/repos/os/include/nic_session/client.h +++ b/repos/os/include/nic_session/client.h @@ -56,6 +56,13 @@ class Nic::Session_client : public Genode::Rpc_client Rx *rx_channel() { return &_rx; } Tx::Source *tx() { return _tx.source(); } Rx::Sink *rx() { return _rx.sink(); } + + void link_state_sigh(Genode::Signal_context_capability sigh) override + { + call(sigh); + } + + bool link_state() override { return call(); } }; #endif /* _INCLUDE__NIC_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/nic_session/nic_session.h b/repos/os/include/nic_session/nic_session.h index 239f033a1e..15e79c858e 100644 --- a/repos/os/include/nic_session/nic_session.h +++ b/repos/os/include/nic_session/nic_session.h @@ -93,6 +93,15 @@ struct Nic::Session : Genode::Session */ virtual Rx::Sink *rx() { return 0; } + /** + * Request current link state of network adapter (true means link detected) + */ + virtual bool link_state() = 0; + + /** + * Register signal handler for link state changes + */ + virtual void link_state_sigh(Genode::Signal_context_capability sigh) = 0; /******************* ** RPC interface ** @@ -101,8 +110,12 @@ struct Nic::Session : Genode::Session GENODE_RPC(Rpc_mac_address, Mac_address, mac_address); GENODE_RPC(Rpc_tx_cap, Genode::Capability, _tx_cap); GENODE_RPC(Rpc_rx_cap, Genode::Capability, _rx_cap); + GENODE_RPC(Rpc_link_state, bool, link_state); + GENODE_RPC(Rpc_link_state_sigh, void, link_state_sigh, + Genode::Signal_context_capability); - GENODE_RPC_INTERFACE(Rpc_mac_address, Rpc_tx_cap, Rpc_rx_cap); + GENODE_RPC_INTERFACE(Rpc_mac_address, Rpc_link_state, + Rpc_link_state_sigh, Rpc_tx_cap, Rpc_rx_cap); }; #endif /* _INCLUDE__NIC_SESSION__NIC_SESSION_H_ */ diff --git a/repos/os/src/drivers/nic/lan9118/lan9118.h b/repos/os/src/drivers/nic/lan9118/lan9118.h index 9ea7c33f53..40abc3cc2f 100644 --- a/repos/os/src/drivers/nic/lan9118/lan9118.h +++ b/repos/os/src/drivers/nic/lan9118/lan9118.h @@ -72,6 +72,7 @@ class Lan9118 : public Nic::Driver Timer::Connection _timer; Nic::Rx_buffer_alloc &_rx_buffer_alloc; Nic::Mac_address _mac_addr; + Nic::Driver_notification &_notify; enum { IRQ_STACK_SIZE = 4096 }; Genode::Irq_activation _irq_activation; @@ -201,11 +202,13 @@ class Lan9118 : public Nic::Driver * \throw Device_not_supported */ Lan9118(Genode::addr_t mmio_base, Genode::size_t mmio_size, int irq, - Nic::Rx_buffer_alloc &rx_buffer_alloc) + Nic::Rx_buffer_alloc &rx_buffer_alloc, + Nic::Driver_notification ¬ify) : _mmio(mmio_base, mmio_size), _reg_base(_mmio.local_addr()), _rx_buffer_alloc(rx_buffer_alloc), + _notify(notify), _irq_activation(irq, *this, IRQ_STACK_SIZE) { unsigned long const id_rev = _reg_read(ID_REV), @@ -287,6 +290,8 @@ class Lan9118 : public Nic::Driver _mac_csr_write(MAC_CR, 0); } + void link_state_changed() { _notify.link_state_changed(); } + /*************************** ** Nic::Driver interface ** @@ -297,6 +302,12 @@ class Lan9118 : public Nic::Driver return _mac_addr; } + bool link_state() + { + /* XXX always return true for now */ + return true; + } + void tx(char const *packet, Genode::size_t size) { /* limit size to 11 bits, the maximum supported by lan9118 */ diff --git a/repos/os/src/drivers/nic/lan9118/main.cc b/repos/os/src/drivers/nic/lan9118/main.cc index dcf8abc618..1caa92c701 100644 --- a/repos/os/src/drivers/nic/lan9118/main.cc +++ b/repos/os/src/drivers/nic/lan9118/main.cc @@ -37,10 +37,11 @@ int main(int, char **) */ struct Lan9118_driver_factory : Nic::Driver_factory { - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc) + Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, + Nic::Driver_notification ¬ify) { return new (env()->heap()) - Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, alloc); + Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, alloc, notify); } void destroy(Nic::Driver *driver) diff --git a/repos/os/src/drivers/nic/linux/main.cc b/repos/os/src/drivers/nic/linux/main.cc index ac2d59be20..0db6e601b0 100644 --- a/repos/os/src/drivers/nic/linux/main.cc +++ b/repos/os/src/drivers/nic/linux/main.cc @@ -67,8 +67,9 @@ class Linux_driver : public Nic::Driver } }; - Nic::Mac_address _mac_addr; - Nic::Rx_buffer_alloc &_alloc; + Nic::Mac_address _mac_addr; + Nic::Rx_buffer_alloc &_alloc; + Nic::Driver_notification &_notify; char _packet_buffer[1514]; /* maximum ethernet packet length */ int _tap_fd; @@ -114,8 +115,11 @@ class Linux_driver : public Nic::Driver public: - Linux_driver(Nic::Rx_buffer_alloc &alloc) - : _alloc(alloc), _tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, *this) + Linux_driver(Nic::Rx_buffer_alloc &alloc, + Nic::Driver_notification ¬ify) + : + _alloc(alloc), _notify(notify), + _tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, *this) { /* try using configured MAC address */ try { @@ -141,6 +145,8 @@ class Linux_driver : public Nic::Driver _rx_thread.start(); } + void link_state_changed() { _notify.link_state_changed(); } + /*************************** ** Nic::Driver interface ** @@ -148,6 +154,12 @@ class Linux_driver : public Nic::Driver Nic::Mac_address mac_address() { return _mac_addr; } + bool link_state() + { + /* XXX return always true for now */ + return true; + } + void tx(char const *packet, Genode::size_t size) { int ret; @@ -200,9 +212,10 @@ int main(int, char **) */ struct Linux_driver_factory : Nic::Driver_factory { - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc) + Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, + Nic::Driver_notification ¬ify) { - return new (env()->heap()) Linux_driver(alloc); + return new (env()->heap()) Linux_driver(alloc, notify); } void destroy(Nic::Driver *driver) diff --git a/repos/os/src/server/nic_bridge/component.cc b/repos/os/src/server/nic_bridge/component.cc index d3e8fbc82f..7fc2255dd1 100644 --- a/repos/os/src/server/nic_bridge/component.cc +++ b/repos/os/src/server/nic_bridge/component.cc @@ -102,6 +102,10 @@ void Session_component::_free_ipv4_node() } +bool Session_component::link_state() { + return Net::Env::nic()->link_state(); } + + void Session_component::set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr) { _free_ipv4_node(); diff --git a/repos/os/src/server/nic_bridge/component.h b/repos/os/src/server/nic_bridge/component.h index 41ff3d1f80..dbec9ea1ef 100644 --- a/repos/os/src/server/nic_bridge/component.h +++ b/repos/os/src/server/nic_bridge/component.h @@ -105,6 +105,8 @@ namespace Net { Mac_address_node _mac_node; Ipv4_address_node *_ipv4_node; + Genode::Signal_context_capability _link_state_sigh; + void _free_ipv4_node(); public: @@ -137,8 +139,23 @@ namespace Net { return m; } + void link_state_changed() + { + if (_link_state_sigh.valid()) + Genode::Signal_transmitter(_link_state_sigh).submit(); + } + void set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr); + /**************************************** + ** Nic::Driver notification interface ** + ****************************************/ + + bool link_state(); + + void link_state_sigh(Genode::Signal_context_capability sigh) { + _link_state_sigh = sigh; } + /****************************** ** Packet_handler interface ** ******************************/ diff --git a/repos/os/src/server/nic_bridge/nic.cc b/repos/os/src/server/nic_bridge/nic.cc index 12f3e3b376..80dbad6763 100644 --- a/repos/os/src/server/nic_bridge/nic.cc +++ b/repos/os/src/server/nic_bridge/nic.cc @@ -134,4 +134,5 @@ Net::Nic::Nic() _nic.rx_channel()->sigh_packet_avail(_sink_submit); _nic.tx_channel()->sigh_ack_avail(_source_ack); _nic.tx_channel()->sigh_ready_to_submit(_source_submit); + _nic.link_state_sigh(_client_link_state); } diff --git a/repos/os/src/server/nic_bridge/nic.h b/repos/os/src/server/nic_bridge/nic.h index b93a83dc63..f143886c01 100644 --- a/repos/os/src/server/nic_bridge/nic.h +++ b/repos/os/src/server/nic_bridge/nic.h @@ -45,6 +45,7 @@ class Net::Nic : public Net::Packet_handler ::Nic::Connection *nic() { return &_nic; } Ethernet_frame::Mac_address mac() { return _mac; } + bool link_state() { return _nic.link_state(); } /****************************** ** Packet_handler interface ** diff --git a/repos/os/src/server/nic_bridge/packet_handler.cc b/repos/os/src/server/nic_bridge/packet_handler.cc index 43bbafe777..cec9f13f23 100644 --- a/repos/os/src/server/nic_bridge/packet_handler.cc +++ b/repos/os/src/server/nic_bridge/packet_handler.cc @@ -54,6 +54,16 @@ void Packet_handler::_ready_to_ack(unsigned) } +void Packet_handler::_link_state(unsigned) +{ + Mac_address_node *node = Env::vlan()->mac_list()->first(); + while (node) { + node->component()->link_state_changed(); + node = node->next(); + } +} + + void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t size) { /* check whether it's really a broadcast packet */ @@ -121,5 +131,6 @@ Packet_handler::Packet_handler() : _sink_ack(*Net::Env::receiver(), *this, &Packet_handler::_ack_avail), _sink_submit(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_submit), _source_ack(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_ack), - _source_submit(*Net::Env::receiver(), *this, &Packet_handler::_packet_avail) + _source_submit(*Net::Env::receiver(), *this, &Packet_handler::_packet_avail), + _client_link_state(*Net::Env::receiver(), *this, &Packet_handler::_link_state) { } diff --git a/repos/os/src/server/nic_bridge/packet_handler.h b/repos/os/src/server/nic_bridge/packet_handler.h index 8e33afcdbe..cd400628b0 100644 --- a/repos/os/src/server/nic_bridge/packet_handler.h +++ b/repos/os/src/server/nic_bridge/packet_handler.h @@ -65,12 +65,18 @@ class Net::Packet_handler */ void _packet_avail(unsigned) { } + /** + * the link-state of changed + */ + void _link_state(unsigned); + protected: Genode::Signal_dispatcher _sink_ack; Genode::Signal_dispatcher _sink_submit; Genode::Signal_dispatcher _source_ack; Genode::Signal_dispatcher _source_submit; + Genode::Signal_dispatcher _client_link_state; public: diff --git a/repos/os/src/server/nic_loopback/main.cc b/repos/os/src/server/nic_loopback/main.cc index 73835f0317..665b9e63b6 100644 --- a/repos/os/src/server/nic_loopback/main.cc +++ b/repos/os/src/server/nic_loopback/main.cc @@ -142,6 +142,14 @@ namespace Nic { Mac_address result = {{1,2,3,4,5,6}}; return result; } + + bool link_state() + { + /* XXX always return true, for now */ + return true; + } + + void link_state_sigh(Genode::Signal_context_capability sigh) { } }; class Root : public Genode::Root_component diff --git a/repos/ports/src/app/openvpn/main.cc b/repos/ports/src/app/openvpn/main.cc index 050466cef7..2b14aca824 100644 --- a/repos/ports/src/app/openvpn/main.cc +++ b/repos/ports/src/app/openvpn/main.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2014 Genode Labs GmbH + * Copyright (C) 2014-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -87,8 +87,9 @@ class Nic_driver : public Tuntap_device, { private: - Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }}; - Nic::Rx_buffer_alloc &_alloc; + Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }}; + Nic::Rx_buffer_alloc &_alloc; + Nic::Driver_notification &_notify; char const *_packet; @@ -101,10 +102,9 @@ class Nic_driver : public Tuntap_device, public: - Nic_driver(Nic::Rx_buffer_alloc &alloc) + Nic_driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify) : - _alloc(alloc), - _packet(0) + _alloc(alloc), _notify(notify), _packet(0) { if (pipe(_pipefd)) { PERR("could not create pipe"); @@ -114,6 +114,7 @@ class Nic_driver : public Tuntap_device, ~Nic_driver() { PDBG("should probably be implemented"); } + void link_state_changed() { _notify.link_state_changed(); } /*************************** ** Nic::Driver interface ** @@ -121,6 +122,12 @@ class Nic_driver : public Tuntap_device, Nic::Mac_address mac_address() { return _mac_addr; } + bool link_state() + { + /* XXX always return true for now */ + return true; + } + void tx(char const *packet, Genode::size_t size) { PDBGV("packet:0x%p size:%zu", packet, size); @@ -185,11 +192,12 @@ struct Main Nic_driver *drv { 0 }; Openvpn_thread *openvpn { 0 }; - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc) + Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, + Nic::Driver_notification ¬ify) { /* there can be only one */ if (!drv) { - drv = new (Genode::env()->heap()) Nic_driver(alloc); + drv = new (Genode::env()->heap()) Nic_driver(alloc, notify); /** * Setting the pointer in this manner is quite hackish but it has