diff --git a/os/include/net/ipv4.h b/os/include/net/ipv4.h index 571f9327eb..b512f18298 100644 --- a/os/include/net/ipv4.h +++ b/os/include/net/ipv4.h @@ -57,6 +57,8 @@ namespace Net { static const Ipv4_address CURRENT; /* current network */ static const Ipv4_address BROADCAST; /* broadcast address */ + static Ipv4_address ip_from_string(const char *ip); + private: /************************ diff --git a/os/lib/mk/net.mk b/os/lib/mk/net.mk index fa026ce1db..5bb41f45e9 100644 --- a/os/lib/mk/net.mk +++ b/os/lib/mk/net.mk @@ -1,3 +1,3 @@ -SRC_CC = ethernet.cc +SRC_CC = ethernet.cc ipv4.cc vpath %.cc $(REP_DIR)/src/lib/net \ No newline at end of file diff --git a/os/src/lib/net/ipv4.cc b/os/src/lib/net/ipv4.cc index 03eeea664f..bf8982f03c 100644 --- a/os/src/lib/net/ipv4.cc +++ b/os/src/lib/net/ipv4.cc @@ -11,7 +11,57 @@ * under the terms of the GNU General Public License version 2. */ +#include +#include + #include -const Net::Ipv4_packet::Ipv4_address Net::Ipv4_packet::CURRENT(0x00); -const Net::Ipv4_packet::Ipv4_address Net::Ipv4_packet::BROADCAST(0xFF); +using namespace Net; + +struct Scanner_policy_number +{ + static bool identifier_char(char c, unsigned i ) { + return Genode::is_digit(c) && c !='.'; } +}; + +typedef ::Genode::Token Token; + + +Ipv4_packet::Ipv4_address Ipv4_packet::ip_from_string(const char *ip) +{ + Ipv4_address ip_addr; + Token t(ip); + char tmpstr[4]; + int cnt = 0; + unsigned char ipb[4] = {0}; + + while(t) { + if (t.type() == Token::WHITESPACE || t[0] == '.') { + t = t.next(); + continue; + } + t.string(tmpstr, sizeof(tmpstr)); + + unsigned long tmpc = 0; + Genode::ascii_to(tmpstr, &tmpc, 10); + ipb[cnt] = tmpc & 0xFF; + t = t.next(); + + if (cnt == 4) + break; + cnt++; + } + + if (cnt == 4) { + ip_addr.addr[0] = ipb[0]; + ip_addr.addr[1] = ipb[1]; + ip_addr.addr[2] = ipb[2]; + ip_addr.addr[3] = ipb[3]; + } + + return ip_addr; +} + + +const Ipv4_packet::Ipv4_address Ipv4_packet::CURRENT((Genode::uint8_t)0x00); +const Ipv4_packet::Ipv4_address Ipv4_packet::BROADCAST((Genode::uint8_t)0xFF); diff --git a/os/src/server/nic_bridge/address_node.cc b/os/src/server/nic_bridge/address_node.cc deleted file mode 100644 index 4767eb4dfd..0000000000 --- a/os/src/server/nic_bridge/address_node.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * \brief Address-node holds a client-specific session-component. - * \author Stefan Kalkowski - * \date 2010-08-25 - */ - -/* - * Copyright (C) 2010-2013 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. - */ - -#include - -#include "address_node.h" -#include "component.h" - -/** - * Let the client a receive a network packet. - * - * \param addr start address network packet. - * \param size size of network packet. - */ -template -void Net::Address_node::receive_packet(void *addr, Genode::size_t size) -{ - Genode::Lock::Guard lock_guard(*_component->rx_lock()); - - Nic::Session::Rx::Source *source = _component->rx_source(); - - while (true) { - /* flush remaining acknowledgements */ - while (source->ack_avail()) - source->release_packet(source->get_acked_packet()); - - try { - /* allocate packet in rx channel */ - Packet_descriptor rx_packet = source->alloc_packet(size); - - Genode::memcpy((void*)source->packet_content(rx_packet), - (void*)addr, size); - source->submit_packet(rx_packet); - return; - } catch (Nic::Session::Rx::Source::Packet_alloc_failed) { } - } -} - - -/** - * Let the compiler know, for which template instances this implementation - * is used for. - */ -template void Net::Ipv4_address_node::receive_packet(void *addr, Genode::size_t size); -template void Net::Mac_address_node::receive_packet(void *addr, Genode::size_t size); diff --git a/os/src/server/nic_bridge/address_node.h b/os/src/server/nic_bridge/address_node.h index 9fab3f4553..369fcd2ca4 100644 --- a/os/src/server/nic_bridge/address_node.h +++ b/os/src/server/nic_bridge/address_node.h @@ -65,14 +65,6 @@ namespace Net { Address addr() { return _addr; } Session_component *component() { return _component; } - /** - * Let this client node, receive a network-packet - * - * \param addr start address of network packet - * \param size size of network packet - */ - void receive_packet(void *addr, Genode::size_t size); - /************************ ** Avl node interface ** diff --git a/os/src/server/nic_bridge/component.cc b/os/src/server/nic_bridge/component.cc index c13ffb02e4..1048222ed8 100644 --- a/os/src/server/nic_bridge/component.cc +++ b/os/src/server/nic_bridge/component.cc @@ -16,44 +16,17 @@ #include #include -#include -#include - +#include "env.h" #include "component.h" +#include "nic.h" #include "vlan.h" using namespace Net; -const int Session_component::verbose = 1; - -void Session_component::Tx_handler::acknowledge_last_one() -{ - if (!_tx_packet.valid()) - return; - - if (!_component->tx_sink()->ready_to_ack()) - PDBG("need to wait until ready-for-ack"); - _component->tx_sink()->acknowledge_packet(_tx_packet); -} +static const int verbose = 1; -void Session_component::Tx_handler::next_packet(void** src, Genode::size_t *size) -{ - while (true) { - /* block for a new packet */ - _tx_packet = _component->tx_sink()->get_packet(); - if (!_tx_packet.valid()) { - PWRN("received invalid packet"); - continue; - } - *src = _component->tx_sink()->packet_content(_tx_packet); - *size = _tx_packet.size(); - return; - } -} - - -bool Session_component::Tx_handler::handle_arp(Ethernet_frame *eth, Genode::size_t size) +bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size) { Arp_packet *arp = new (eth->data()) Arp_packet(size - sizeof(Ethernet_frame)); @@ -71,18 +44,18 @@ bool Session_component::Tx_handler::handle_arp(Ethernet_frame *eth, Genode::size if (arp->src_ip() == arp->dst_ip()) return false; - Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first(); + Ipv4_address_node *node = Env::vlan()->ip_tree()->first(); if (node) node = node->find_by_address(arp->dst_ip()); if (!node) { - arp->src_mac(_mac); + arp->src_mac(Net::Env::nic()->mac()); } } return true; } -bool Session_component::Tx_handler::handle_ip(Ethernet_frame *eth, Genode::size_t size) +bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size) { Ipv4_packet *ip = new (eth->data()) Ipv4_packet(size - sizeof(Ethernet_frame)); @@ -104,137 +77,84 @@ bool Session_component::Tx_handler::handle_ip(Ethernet_frame *eth, Genode::size_ } -void Session_component::Tx_handler::finalize_packet(Ethernet_frame *eth, +void Session_component::finalize_packet(Ethernet_frame *eth, Genode::size_t size) { - Mac_address_node *node = Vlan::vlan()->mac_tree()->first(); + Mac_address_node *node = Env::vlan()->mac_tree()->first(); if (node) node = node->find_by_address(eth->dst()); if (node) - node->receive_packet((void*) eth, size); - else - send_to_nic(eth, size); + node->component()->send(eth, size); + else { + /* set our MAC as sender */ + eth->src(Net::Env::nic()->mac()); + Net::Env::nic()->send(eth, size); + } } void Session_component::_free_ipv4_node() { if (_ipv4_node) { - Vlan::vlan()->ip_tree()->remove(_ipv4_node); + Env::vlan()->ip_tree()->remove(_ipv4_node); destroy(this->guarded_allocator(), _ipv4_node); } } -struct Scanner_policy_number -{ - static bool identifier_char(char c, unsigned i ) - { - return Genode::is_digit(c) && c !='.'; - } -}; - - -typedef ::Genode::Token Token; - - -Ipv4_packet::Ipv4_address Session_component::ip_from_string(const char *ip) -{ - Ipv4_packet::Ipv4_address ip_addr; - - Token t(ip); - char tmpstr[4]; - int cnt = 0; - unsigned char ipb[4] = {0}; - - while(t) { - - if (t.type() == Token::WHITESPACE || t[0] == '.') { - t = t.next(); - continue; - } - t.string(tmpstr, sizeof(tmpstr)); - - unsigned long tmpc = 0; - Genode::ascii_to(tmpstr, &tmpc, 10); - - ipb[cnt] = tmpc & 0xFF; - - t = t.next(); - - if (cnt == 4) - break; - cnt++; - } - - if (cnt == 4) { - ip_addr.addr[0] = ipb[0]; - ip_addr.addr[1] = ipb[1]; - ip_addr.addr[2] = ipb[2]; - ip_addr.addr[3] = ipb[3]; - } - - return ip_addr; -} - - - -Session_component::Session_component(Genode::Allocator *allocator, - Genode::size_t amount, - Genode::size_t tx_buf_size, - Genode::size_t rx_buf_size, - Ethernet_frame::Mac_address vmac, - Nic::Connection *session, - Genode::Rpc_entrypoint &ep, - char *ip_addr) -: Guarded_range_allocator(allocator, amount), - Tx_rx_communication_buffers(tx_buf_size, rx_buf_size), - Session_rpc_object(Tx_rx_communication_buffers::tx_ds(), - Tx_rx_communication_buffers::rx_ds(), - this->range_allocator(), ep), - _tx_handler(session, this), - _mac_node(vmac, this), - _ipv4_node(0) -{ - Vlan::vlan()->mac_tree()->insert(&_mac_node); - Vlan::vlan()->mac_list()->insert(&_mac_node); - - /* start handler */ - _tx_handler.start(); - _tx_handler.wait_for_startup(); - - /* static ip parsing */ - if (ip_addr != 0 && Genode::strlen(ip_addr)) { - - Ipv4_packet::Ipv4_address ip = ip_from_string(ip_addr); - - if (ip == Ipv4_packet::Ipv4_address()) { - PDBG("Empty or error ip address. Skipped."); - } else { - - set_ipv4_address(ip); - - if (verbose) - PDBG("\nmac=%02x.%02x.%02x.%02x.%02x.%02x ip=%d.%d.%d.%d", - vmac.addr[0], vmac.addr[1], vmac.addr[2], vmac.addr[3], vmac.addr[4], vmac.addr[5], - ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3] - ); - } - } -} - - -Session_component::~Session_component() { - Vlan::vlan()->mac_tree()->remove(&_mac_node); - Vlan::vlan()->mac_list()->remove(&_mac_node); - _free_ipv4_node(); -} - - void Session_component::set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr) { _free_ipv4_node(); _ipv4_node = new (this->guarded_allocator()) Ipv4_address_node(ip_addr, this); - Vlan::vlan()->ip_tree()->insert(_ipv4_node); + Net::Env::vlan()->ip_tree()->insert(_ipv4_node); +} + + +Session_component::Session_component(Genode::Allocator *allocator, + Genode::size_t amount, + Genode::size_t tx_buf_size, + Genode::size_t rx_buf_size, + Ethernet_frame::Mac_address vmac, + Genode::Rpc_entrypoint &ep, + char *ip_addr) +: Guarded_range_allocator(allocator, amount), + Tx_rx_communication_buffers(tx_buf_size, rx_buf_size), + Session_rpc_object(Tx_rx_communication_buffers::tx_ds(), + Tx_rx_communication_buffers::rx_ds(), + this->range_allocator(), ep), + _mac_node(vmac, this), + _ipv4_node(0) +{ + Env::vlan()->mac_tree()->insert(&_mac_node); + Env::vlan()->mac_list()->insert(&_mac_node); + + /* static ip parsing */ + if (ip_addr != 0 && Genode::strlen(ip_addr)) { + Ipv4_packet::Ipv4_address ip = Ipv4_packet::ip_from_string(ip_addr); + + if (ip == Ipv4_packet::Ipv4_address()) { + PWRN("Empty or error ip address. Skipped."); + } else { + set_ipv4_address(ip); + + if (verbose) + PDBG("\nmac=%02x.%02x.%02x.%02x.%02x.%02x ip=%d.%d.%d.%d", + vmac.addr[0], vmac.addr[1], vmac.addr[2], + vmac.addr[3], vmac.addr[4], vmac.addr[5], + ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3]); + } + } + + _tx.sigh_ready_to_ack(_sink_ack); + _tx.sigh_packet_avail(_sink_submit); + _rx.sigh_ack_avail(_source_ack); + _rx.sigh_ready_to_submit(_source_submit); +} + + +Session_component::~Session_component() { + Env::vlan()->mac_tree()->remove(&_mac_node); + Env::vlan()->mac_list()->remove(&_mac_node); + _free_ipv4_node(); } diff --git a/os/src/server/nic_bridge/component.h b/os/src/server/nic_bridge/component.h index aeec3d381e..9be5045b0b 100644 --- a/os/src/server/nic_bridge/component.h +++ b/os/src/server/nic_bridge/component.h @@ -40,7 +40,7 @@ namespace Net { private: Genode::Allocator_guard _guarded_alloc; - Nic::Packet_allocator _range_alloc; + ::Nic::Packet_allocator _range_alloc; public: @@ -97,41 +97,15 @@ namespace Net { */ class Session_component : public Guarded_range_allocator, private Tx_rx_communication_buffers, - public Nic::Session_rpc_object + public ::Nic::Session_rpc_object, + public Packet_handler { private: - class Tx_handler : public Packet_handler - { - private: - - Packet_descriptor _tx_packet; - Session_component *_component; - - void acknowledge_last_one(); - void next_packet(void** src, Genode::size_t *size); - bool handle_arp(Ethernet_frame *eth, Genode::size_t size); - bool handle_ip(Ethernet_frame *eth, Genode::size_t size); - void finalize_packet(Ethernet_frame *eth, Genode::size_t size); - - public: - - Tx_handler(Nic::Connection *session, - Session_component *component) - : Packet_handler(session), _component(component) {} - }; - - - Tx_handler _tx_handler; Mac_address_node _mac_node; Ipv4_address_node *_ipv4_node; - Genode::Lock _rx_lock; - - static const int verbose; void _free_ipv4_node(); - - Ipv4_packet::Ipv4_address ip_from_string(const char *ip); public: @@ -150,25 +124,34 @@ namespace Net { Genode::size_t tx_buf_size, Genode::size_t rx_buf_size, Ethernet_frame::Mac_address vmac, - Nic::Connection *session, Genode::Rpc_entrypoint &ep, char *ip_addr = 0); ~Session_component(); - Nic::Session::Tx::Sink* tx_sink() { return _tx.sink(); } - Nic::Session::Rx::Source* rx_source() { return _rx.source(); } - Genode::Lock* rx_lock() { return &_rx_lock; } - - Nic::Mac_address mac_address() + ::Nic::Mac_address mac_address() { - Nic::Mac_address m; + ::Nic::Mac_address m; Mac_address_node::Address mac = _mac_node.addr(); Genode::memcpy(&m, mac.addr, sizeof(m.addr)); return m; } void set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr); + + /****************************** + ** Packet_handler interface ** + ******************************/ + + Packet_stream_sink< ::Nic::Session::Policy> * sink() { + return _tx.sink(); } + + Packet_stream_source< ::Nic::Session::Policy> * source() { + return _rx.source(); } + + bool handle_arp(Ethernet_frame *eth, Genode::size_t size); + bool handle_ip(Ethernet_frame *eth, Genode::size_t size); + void finalize_packet(Ethernet_frame *eth, Genode::size_t size); }; @@ -182,7 +165,6 @@ namespace Net { enum { verbose = 1 }; Mac_allocator _mac_alloc; - Nic::Connection *_session; Genode::Rpc_entrypoint &_ep; protected: @@ -240,10 +222,8 @@ namespace Net { tx_buf_size, rx_buf_size, _mac_alloc.alloc(), - _session, _ep, - ip_addr - ); + ip_addr); } catch(Mac_allocator::Alloc_failed) { PWRN("Mac address allocation failed!"); return (Session_component*) 0; @@ -253,10 +233,9 @@ namespace Net { public: Root(Genode::Rpc_entrypoint *session_ep, - Genode::Allocator *md_alloc, - Nic::Connection *session) + Genode::Allocator *md_alloc) : Genode::Root_component(session_ep, md_alloc), - _session(session), _ep(*session_ep) { } + _ep(*session_ep) { } }; } /* namespace Net */ diff --git a/os/src/server/nic_bridge/env.cc b/os/src/server/nic_bridge/env.cc new file mode 100644 index 0000000000..6b6973971b --- /dev/null +++ b/os/src/server/nic_bridge/env.cc @@ -0,0 +1,36 @@ +/* + * \brief Nic-bridge global environment + * \author Stefan Kalkowski + * \date 2013-05-23 + */ + +/* + * Copyright (C) 2013 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. + */ + +#include "env.h" +#include "nic.h" +#include "vlan.h" + +Genode::Signal_receiver* Net::Env::receiver() +{ + static Genode::Signal_receiver receiver; + return &receiver; +} + + +Net::Vlan* Net::Env::vlan() +{ + static Net::Vlan vlan; + return &vlan; +} + + +Net::Nic* Net::Env::nic() +{ + static Net::Nic nic; + return &nic; +} diff --git a/os/src/server/nic_bridge/env.h b/os/src/server/nic_bridge/env.h new file mode 100644 index 0000000000..6b134436de --- /dev/null +++ b/os/src/server/nic_bridge/env.h @@ -0,0 +1,36 @@ +/* + * \brief Proxy-ARP environment + * \author Stefan Kalkowski + * \date 2013-05-24 + * + * A database containing all clients sorted by IP and MAC addresses. + */ + +/* + * Copyright (C) 2013 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. + */ + +#ifndef _SRC__SERVER__NIC_BRIDGE__ENV_H_ +#define _SRC__SERVER__NIC_BRIDGE__ENV_H_ + +#include + +namespace Net { + class Vlan; + class Nic; + class Env; +} + +struct Net::Env +{ + static Genode::Signal_receiver* receiver(); + + static Vlan *vlan(); + + static Net::Nic *nic(); +}; + +#endif /* _SRC__SERVER__NIC_BRIDGE__ENV_H_ */ diff --git a/os/src/server/nic_bridge/main.cc b/os/src/server/nic_bridge/main.cc index 7afae9e03d..5b50474a9c 100644 --- a/os/src/server/nic_bridge/main.cc +++ b/os/src/server/nic_bridge/main.cc @@ -13,32 +13,21 @@ /* Genode */ #include -#include #include #include #include #include #include -#include "packet_handler.h" +/* local includes */ #include "component.h" +#include "env.h" int main(int, char **) { using namespace Genode; - enum { STACK_SIZE = 4096 }; - static Cap_connection cap; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_bridge_ep"); - - static Nic::Packet_allocator tx_block_alloc(env()->heap()); - - enum { - PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE, - BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE, - }; - /* read MAC address prefix from config file */ try { Nic::Mac_address mac; @@ -47,23 +36,22 @@ int main(int, char **) sizeof(Net::Mac_allocator::mac_addr_base)); } catch(...) {} - Root_capability nic_root_cap; try { - static Nic::Connection nic(&tx_block_alloc, BUF_SIZE, BUF_SIZE); - static Net::Rx_handler rx_handler(&nic); - static Net::Root nic_root(&ep, env()->heap(), &nic); - - /* start receiver thread handling packets from the NIC driver */ - rx_handler.start(); - rx_handler.wait_for_startup(); + enum { STACK_SIZE = 4096 }; + static Cap_connection cap; + static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_bridge_ep"); + static Net::Root nic_root(&ep, env()->heap()); /* announce NIC service */ env()->parent()->announce(ep.manage(&nic_root)); + while (true) { + Signal s = Net::Env::receiver()->wait_for_signal(); + static_cast(s.context())->dispatch(s.num()); + } } catch (Parent::Service_denied) { PERR("Could not connect to uplink NIC"); } - sleep_forever(); return 0; } diff --git a/os/src/server/nic_bridge/nic.cc b/os/src/server/nic_bridge/nic.cc new file mode 100644 index 0000000000..12f41382ae --- /dev/null +++ b/os/src/server/nic_bridge/nic.cc @@ -0,0 +1,136 @@ +/* + * \brief NIC handler + * \author Stefan Kalkowski + * \date 2013-05-24 + */ + +/* + * Copyright (C) 2013 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "address_node.h" +#include "component.h" +#include "env.h" +#include "nic.h" +#include "vlan.h" + +using namespace Net; + + +bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) { + Arp_packet *arp = new (eth->data()) + Arp_packet(size - sizeof(Ethernet_frame)); + + /* ignore broken packets */ + if (!arp->ethernet_ipv4()) + return true; + + /* look whether the IP address is one of our client's */ + Ipv4_address_node *node = Env::vlan()->ip_tree()->first(); + if (node) + node = node->find_by_address(arp->dst_ip()); + if (node) { + if (arp->opcode() == Arp_packet::REQUEST) { + /* + * The ARP packet gets re-written, we interchange source + * and destination MAC and IP addresses, and set the opcode + * to reply, and then push the packet back to the NIC driver. + */ + Ipv4_packet::Ipv4_address old_src_ip = arp->src_ip(); + arp->opcode(Arp_packet::REPLY); + arp->dst_mac(arp->src_mac()); + arp->src_mac(mac()); + arp->src_ip(arp->dst_ip()); + arp->dst_ip(old_src_ip); + eth->dst(arp->dst_mac()); + + /* set our MAC as sender */ + eth->src(mac()); + send(eth, size); + } else { + /* overwrite destination MAC */ + arp->dst_mac(node->component()->mac_address().addr); + eth->dst(node->component()->mac_address().addr); + node->component()->send(eth, size); + } + return false; + } + return true; +} + + +bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) { + Ipv4_packet *ip = new (eth->data()) + Ipv4_packet(size - sizeof(Ethernet_frame)); + + /* is it an UDP packet ? */ + if (ip->protocol() == Udp_packet::IP_ID) + { + Udp_packet *udp = new (ip->data()) + Udp_packet(size - sizeof(Ipv4_packet)); + + /* is it a DHCP packet ? */ + if (Dhcp_packet::is_dhcp(udp)) { + Dhcp_packet *dhcp = new (udp->data()) + Dhcp_packet(size - sizeof(Ipv4_packet) - sizeof(Udp_packet)); + + /* check for DHCP ACKs containing new client ips */ + if (dhcp->op() == Dhcp_packet::REPLY) { + Dhcp_packet::Option *ext = dhcp->option(Dhcp_packet::MSG_TYPE); + if (ext) { + /* + * extract the IP address and set it in the + * client's session-component + */ + Genode::uint8_t *msg_type = (Genode::uint8_t*) ext->value(); + if (*msg_type == Dhcp_packet::DHCP_ACK) { + Mac_address_node *node = + Env::vlan()->mac_tree()->first(); + if (node) + node = node->find_by_address(dhcp->client_mac()); + if (node) + node->component()->set_ipv4_address(dhcp->yiaddr()); + } + } + } + } + } + + /* is it an unicast message to one of our clients ? */ + if (eth->dst() == Net::Env::nic()->mac()) { + Ipv4_address_node *node = Env::vlan()->ip_tree()->first(); + if (node) { + node = node->find_by_address(ip->dst()); + if (node) { + /* overwrite destination MAC */ + eth->dst(node->component()->mac_address().addr); + + /* deliver the packet to the client */ + node->component()->send(eth, size); + return false; + } + } + } + return true; +} + + +Net::Nic::Nic() +: _tx_block_alloc(Genode::env()->heap()), + _nic(&_tx_block_alloc, BUF_SIZE, BUF_SIZE) +{ + _nic.rx_channel()->sigh_ready_to_ack(_sink_ack); + _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); +} diff --git a/os/src/server/nic_bridge/nic.h b/os/src/server/nic_bridge/nic.h new file mode 100644 index 0000000000..e61fd0b8d5 --- /dev/null +++ b/os/src/server/nic_bridge/nic.h @@ -0,0 +1,64 @@ +/* + * \brief Proxy-ARP NIC session handler + * \author Stefan Kalkowski + * \date 2010-08-18 + */ + +/* + * Copyright (C) 2010-2013 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. + */ + +#ifndef _SRC__SERVER__NIC_BRIDGE__NIC_H_ +#define _SRC__SERVER__NIC_BRIDGE__NIC_H_ + +#include +#include + +#include "env.h" +#include "packet_handler.h" + +namespace Net { + class Nic; +} + + +class Net::Nic : public Net::Packet_handler +{ + private: + + enum { + PACKET_SIZE = ::Nic::Packet_allocator::DEFAULT_PACKET_SIZE, + BUF_SIZE = ::Nic::Session::QUEUE_SIZE * PACKET_SIZE, + }; + + ::Nic::Packet_allocator _tx_block_alloc; + ::Nic::Connection _nic; + + public: + + Nic(); + + ::Nic::Connection *nic() { return &_nic; } + + Ethernet_frame::Mac_address mac() { return _nic.mac_address().addr; } + + + /****************************** + ** Packet_handler interface ** + ******************************/ + + Packet_stream_sink< ::Nic::Session::Policy> * sink() { + return _nic.rx(); } + + Packet_stream_source< ::Nic::Session::Policy> * source() { + return _nic.tx(); } + + bool handle_arp(Ethernet_frame *eth, Genode::size_t size); + bool handle_ip(Ethernet_frame *eth, Genode::size_t size); + void finalize_packet(Ethernet_frame *eth, Genode::size_t size) {} +}; + +#endif /* _SRC__SERVER__NIC_BRIDGE__NIC_H_ */ diff --git a/os/src/server/nic_bridge/packet_handler.cc b/os/src/server/nic_bridge/packet_handler.cc index 27c6c7ff69..43bbafe777 100644 --- a/os/src/server/nic_bridge/packet_handler.cc +++ b/os/src/server/nic_bridge/packet_handler.cc @@ -1,5 +1,5 @@ /* - * \brief Thread implementations handling network packets. + * \brief Packet handler handling network packets. * \author Stefan Kalkowski * \date 2010-08-18 */ @@ -18,14 +18,40 @@ #include #include +#include "env.h" #include "component.h" #include "packet_handler.h" #include "vlan.h" using namespace Net; +static const bool verbose = true; -static Genode::Lock _nic_lock; +void Packet_handler::_ready_to_submit(unsigned) +{ + /* as long as packets are available, and we can ack them */ + while (sink()->packet_avail()) { + _packet = sink()->get_packet(); + if (!_packet.valid()) continue; + handle_ethernet(sink()->packet_content(_packet), _packet.size()); + + if (!sink()->ready_to_ack()) { + if (verbose) + PWRN("ack state FULL"); + return; + } + + sink()->acknowledge_packet(_packet); + } +} + + +void Packet_handler::_ready_to_ack(unsigned) +{ + /* check for acknowledgements */ + while (source()->ack_avail()) + source()->release_packet(source()->get_acked_packet()); +} void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t size) @@ -34,202 +60,66 @@ void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t si if (eth->dst() == Ethernet_frame::BROADCAST) { /* iterate through the list of clients */ Mac_address_node *node = - Vlan::vlan()->mac_list()->first(); + Env::vlan()->mac_list()->first(); while (node) { /* deliver packet */ - node->receive_packet((void*) eth, size); + node->component()->send(eth, size); node = node->next(); } } } -void Packet_handler::send_to_nic(Ethernet_frame *eth, Genode::size_t size) +void Packet_handler::handle_ethernet(void* src, Genode::size_t size) { - Genode::Lock::Guard lock_guard(_nic_lock); - - while (true) { - /* check for acknowledgements */ - while (_session->tx()->ack_avail()) { - Packet_descriptor p = - _session->tx()->get_acked_packet(); - _session->tx()->release_packet(p); + try { + /* parse ethernet frame header */ + Ethernet_frame *eth = new (src) Ethernet_frame(size); + switch (eth->type()) { + case Ethernet_frame::ARP: + if (!handle_arp(eth, size)) return; + break; + case Ethernet_frame::IPV4: + if(!handle_ip(eth, size)) return; + break; + default: + ; } - try { - /* set our MAC as sender */ - eth->src(_mac); - - /* allocate packet to NIC driver */ - Packet_descriptor tx_packet = _session->tx()->alloc_packet(size); - char *tx_content = _session->tx()->packet_content(tx_packet); - - /* copy and submit packet */ - Genode::memcpy((void*)tx_content, (void*)eth, size); - _session->tx()->submit_packet(tx_packet); - return; - } catch(Nic::Session::Tx::Source::Packet_alloc_failed) { } + broadcast_to_clients(eth, size); + finalize_packet(eth, size); + } catch(Arp_packet::No_arp_packet) { + PWRN("Invalid ARP packet!"); + } catch(Ethernet_frame::No_ethernet_frame) { + PWRN("Invalid ethernet frame"); + } catch(Dhcp_packet::No_dhcp_packet) { + PWRN("Invalid IPv4 packet!"); + } catch(Ipv4_packet::No_ip_packet) { + PWRN("Invalid IPv4 packet!"); + } catch(Udp_packet::No_udp_packet) { + PWRN("Invalid UDP packet!"); } } -void Packet_handler::entry() +void Packet_handler::send(Ethernet_frame *eth, Genode::size_t size) { - void* src; - Genode::size_t eth_sz; - - /* signal preparedness */ - _startup_sem.up(); - - /* loop for new packets */ - while (true) { - try { - acknowledge_last_one(); - next_packet(&src, ð_sz); - - /* parse ethernet frame header */ - Ethernet_frame *eth = new (src) Ethernet_frame(eth_sz); - switch (eth->type()) { - case Ethernet_frame::ARP: - { - if (!handle_arp(eth, eth_sz)) - continue; - break; - } - case Ethernet_frame::IPV4: - { - if(!handle_ip(eth, eth_sz)) - continue; - break; - } - default: - ; - } - - /* broadcast packet ? */ - broadcast_to_clients(eth, eth_sz); - - finalize_packet(eth, eth_sz); - } catch(Arp_packet::No_arp_packet) { - PWRN("Invalid ARP packet!"); - } catch(Ethernet_frame::No_ethernet_frame) { - PWRN("Invalid ethernet frame"); - } catch(Dhcp_packet::No_dhcp_packet) { - PWRN("Invalid IPv4 packet!"); - } catch(Ipv4_packet::No_ip_packet) { - PWRN("Invalid IPv4 packet!"); - } catch(Udp_packet::No_udp_packet) { - PWRN("Invalid UDP packet!"); - } + try { + /* copy and submit packet */ + Packet_descriptor packet = source()->alloc_packet(size); + char *content = source()->packet_content(packet); + Genode::memcpy((void*)content, (void*)eth, size); + source()->submit_packet(packet); + } catch(Packet_stream_source< ::Nic::Session::Policy>::Packet_alloc_failed) { + if (verbose) + PWRN("Packet dropped"); } } -void Rx_handler::acknowledge_last_one() { - /* acknowledge packet to NIC driver */ - if(_rx_packet.valid()) - _session->rx()->acknowledge_packet(_rx_packet); -} - - -void Rx_handler::next_packet(void** src, Genode::size_t *size) { - /* get next packet from NIC driver */ - _rx_packet = _session->rx()->get_packet(); - *src = _session->rx()->packet_content(_rx_packet); - *size = _rx_packet.size(); -} - - -bool Rx_handler::handle_arp(Ethernet_frame *eth, Genode::size_t size) { - Arp_packet *arp = new (eth->data()) - Arp_packet(size - sizeof(Ethernet_frame)); - - /* ignore broken packets */ - if (!arp->ethernet_ipv4()) - return true; - - /* look whether the IP address is one of our client's */ - Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first(); - if (node) - node = node->find_by_address(arp->dst_ip()); - if (node) { - if (arp->opcode() == Arp_packet::REQUEST) { - /* - * The ARP packet gets re-written, we interchange source - * and destination MAC and IP addresses, and set the opcode - * to reply, and then push the packet back to the NIC driver. - */ - Ipv4_packet::Ipv4_address old_src_ip = arp->src_ip(); - arp->opcode(Arp_packet::REPLY); - arp->dst_mac(arp->src_mac()); - arp->src_mac(_mac); - arp->src_ip(arp->dst_ip()); - arp->dst_ip(old_src_ip); - eth->dst(arp->dst_mac()); - send_to_nic(eth, size); - } else { - /* overwrite destination MAC */ - arp->dst_mac(node->component()->mac_address().addr); - eth->dst(node->component()->mac_address().addr); - node->receive_packet((void*) eth, size); - } - return false; - } - return true; -} - - -bool Rx_handler::handle_ip(Ethernet_frame *eth, Genode::size_t size) { - Ipv4_packet *ip = new (eth->data()) - Ipv4_packet(size - sizeof(Ethernet_frame)); - - /* is it an UDP packet ? */ - if (ip->protocol() == Udp_packet::IP_ID) - { - Udp_packet *udp = new (ip->data()) - Udp_packet(size - sizeof(Ipv4_packet)); - - /* is it a DHCP packet ? */ - if (Dhcp_packet::is_dhcp(udp)) { - Dhcp_packet *dhcp = new (udp->data()) - Dhcp_packet(size - sizeof(Ipv4_packet) - sizeof(Udp_packet)); - - /* check for DHCP ACKs containing new client ips */ - if (dhcp->op() == Dhcp_packet::REPLY) { - Dhcp_packet::Option *ext = dhcp->option(Dhcp_packet::MSG_TYPE); - if (ext) { - /* - * extract the IP address and set it in the - * client's session-component - */ - Genode::uint8_t *msg_type = (Genode::uint8_t*) ext->value(); - if (*msg_type == Dhcp_packet::DHCP_ACK) { - Mac_address_node *node = - Vlan::vlan()->mac_tree()->first(); - if (node) - node = node->find_by_address(dhcp->client_mac()); - if (node) - node->component()->set_ipv4_address(dhcp->yiaddr()); - } - } - } - } - } - - /* is it an unicast message to one of our clients ? */ - if (eth->dst() == _mac) { - Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first(); - if (node) { - node = node->find_by_address(ip->dst()); - if (node) { - /* overwrite destination MAC */ - eth->dst(node->component()->mac_address().addr); - - /* deliver the packet to the client */ - node->receive_packet((void*) eth, size); - return false; - } - } - } - return true; -} +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) +{ } diff --git a/os/src/server/nic_bridge/packet_handler.h b/os/src/server/nic_bridge/packet_handler.h index 98ab415e9f..441c9f9796 100644 --- a/os/src/server/nic_bridge/packet_handler.h +++ b/os/src/server/nic_bridge/packet_handler.h @@ -1,5 +1,5 @@ /* - * \brief Thread implementations handling network packets. + * \brief Signal driven NIC packet handler * \author Stefan Kalkowski * \date 2010-08-18 */ @@ -22,147 +22,111 @@ #include namespace Net { - - /** - * Generic thread-implementation used as base for - * global receiver thread and client's transmit-threads. - */ - class Packet_handler : public Genode::Thread<8192> - { - private: - - Genode::Semaphore _startup_sem; /* thread startup sync */ - - protected: - - Nic::Connection *_session; /* session to nic driver */ - Ethernet_frame::Mac_address _mac; /* real nic's mac */ - - /** - * Broadcasts ethernet frame to all clients, - * as long as its really a broadcast packtet. - * - * \param eth ethernet frame to send. - * \param size ethernet frame's size. - */ - void inline broadcast_to_clients(Ethernet_frame *eth, - Genode::size_t size); - - /** - * Send ethernet frame to NIC driver. - * - * \param eth ethernet frame to send. - * \param size ethernet frame's size. - */ - void send_to_nic(Ethernet_frame *eth, Genode::size_t size); - - /** - * Acknowledge the last processed packet. - */ - virtual void acknowledge_last_one() = 0; - - /** - * Block for the next packet to process. - */ - virtual void next_packet(void** src, - Genode::size_t *size) = 0; - - /* - * Handle an ARP packet - * - * \param eth ethernet frame containing the ARP packet. - * \param size ethernet frame's size. - */ - virtual bool handle_arp(Ethernet_frame *eth, - Genode::size_t size) = 0; - - /* - * Handle an IP packet - * - * \param eth ethernet frame containing the IP packet. - * \param size ethernet frame's size. - */ - virtual bool handle_ip(Ethernet_frame *eth, - Genode::size_t size) = 0; - - /* - * Finalize handling of ethernet frame. - * - * \param eth ethernet frame to handle. - * \param size ethernet frame's size. - */ - virtual void finalize_packet(Ethernet_frame *eth, - Genode::size_t size) {} - - public: - - Packet_handler(Nic::Connection *session) - : _session(session), _mac(session->mac_address().addr) {} - - /* - * Thread's entry code. - */ - void entry(); - - /* - * Block until thread is ready to execute. - */ - void wait_for_startup() { _startup_sem.down(); } - }; - - - /** - * Receiver thread handling network packets from the NIC driver - */ - class Rx_handler : public Packet_handler - { - private: - - Packet_descriptor _rx_packet; /* actual processed packet */ - - /** - * Acknowledge the last processed packet. - */ - void acknowledge_last_one(); - - /** - * Block for the next packet to process. - * - * \param src buffer the network packet gets written to. - * \param size size of packet gets written to. - */ - void next_packet(void** src, Genode::size_t *size); - - /* - * Handle an ARP packet. - * If it's an ARP request for an IP of one of our client's, - * reply directly with the NIC's MAC address. - * - * \param eth ethernet frame containing the ARP packet. - * \param size ethernet frame's size. - */ - bool handle_arp(Ethernet_frame *eth, Genode::size_t size); - - /* - * Handle an IP packet. - * IP packets have to be inspected for DHCP replies. - * If an reply contains a new IP address for one of our - * client's, the client's database needs to be updated. - * - * \param eth ethernet frame containing the IP packet. - * \param size ethernet frame's size. - */ - bool handle_ip(Ethernet_frame *eth, Genode::size_t size); - - public: - - /** - * Constructor - * - * \param session session to NIC driver. - */ - Rx_handler(Nic::Connection *session) : Packet_handler(session) {} - }; + class Packet_handler; } +/** + * Generic packet handler used as base for NIC and client packet handlers. + */ +class Net::Packet_handler +{ + private: + + Packet_descriptor _packet; + + /** + * submit queue not empty anymore + */ + void _ready_to_submit(unsigned); + + /** + * acknoledgement queue not full anymore + * + * TODO: by now, we assume ACK and SUBMIT queue to be equally + * dimensioned. That's why we ignore this signal by now. + */ + void _ack_avail(unsigned) { } + + /** + * acknoledgement queue not empty anymore + */ + void _ready_to_ack(unsigned); + + /** + * submit queue not full anymore + * + * TODO: by now, we just drop packets that cannot be transferred + * to the other side, that's why we ignore this signal. + */ + void _packet_avail(unsigned) { } + + protected: + + Genode::Signal_dispatcher _sink_ack; + Genode::Signal_dispatcher _sink_submit; + Genode::Signal_dispatcher _source_ack; + Genode::Signal_dispatcher _source_submit; + + public: + + Packet_handler(); + + virtual Packet_stream_sink< ::Nic::Session::Policy> * sink() = 0; + virtual Packet_stream_source< ::Nic::Session::Policy> * source() = 0; + + + /** + * Broadcasts ethernet frame to all clients, + * as long as its really a broadcast packtet. + * + * \param eth ethernet frame to send. + * \param size ethernet frame's size. + */ + void inline broadcast_to_clients(Ethernet_frame *eth, + Genode::size_t size); + + /** + * Send ethernet frame + * + * \param eth ethernet frame to send. + * \param size ethernet frame's size. + */ + void send(Ethernet_frame *eth, Genode::size_t size); + + /** + * Handle an ethernet packet + * + * \param src ethernet frame's address + * \param size ethernet frame's size. + */ + void handle_ethernet(void* src, Genode::size_t size); + + /* + * Handle an ARP packet + * + * \param eth ethernet frame containing the ARP packet. + * \param size ethernet frame's size. + */ + virtual bool handle_arp(Ethernet_frame *eth, + Genode::size_t size) = 0; + + /* + * Handle an IP packet + * + * \param eth ethernet frame containing the IP packet. + * \param size ethernet frame's size. + */ + virtual bool handle_ip(Ethernet_frame *eth, + Genode::size_t size) = 0; + + /* + * Finalize handling of ethernet frame. + * + * \param eth ethernet frame to handle. + * \param size ethernet frame's size. + */ + virtual void finalize_packet(Ethernet_frame *eth, + Genode::size_t size) = 0; +}; + #endif /* _PACKET_HANDLER_H_ */ diff --git a/os/src/server/nic_bridge/target.mk b/os/src/server/nic_bridge/target.mk index 64061b0423..d947284ebe 100644 --- a/os/src/server/nic_bridge/target.mk +++ b/os/src/server/nic_bridge/target.mk @@ -1,6 +1,5 @@ TARGET = nic_bridge LIBS = base net -SRC_CC = address_node.cc component.cc mac.cc \ - main.cc packet_handler.cc vlan.cc +SRC_CC = component.cc env.cc mac.cc main.cc nic.cc packet_handler.cc vpath *.cc $(REP_DIR)/src/server/proxy_arp diff --git a/os/src/server/nic_bridge/vlan.cc b/os/src/server/nic_bridge/vlan.cc deleted file mode 100644 index ba2f34da3c..0000000000 --- a/os/src/server/nic_bridge/vlan.cc +++ /dev/null @@ -1,20 +0,0 @@ -/* - * \brief Virtual local network. - * \author Stefan Kalkowski - * \date 2010-08-18 - */ - -/* - * Copyright (C) 2010-2013 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. - */ - -#include "vlan.h" - -Net::Vlan* Net::Vlan::vlan() -{ - static Net::Vlan vlan; - return &vlan; -} diff --git a/os/src/server/nic_bridge/vlan.h b/os/src/server/nic_bridge/vlan.h index 3c64e537ed..eb86ffca35 100644 --- a/os/src/server/nic_bridge/vlan.h +++ b/os/src/server/nic_bridge/vlan.h @@ -40,17 +40,14 @@ namespace Net { Mac_address_list _mac_list; Ipv4_address_tree _ip_tree; - Vlan() {} - public: + Vlan() {} + Mac_address_tree *mac_tree() { return &_mac_tree; } Mac_address_list *mac_list() { return &_mac_list; } Ipv4_address_tree *ip_tree() { return &_ip_tree; } - - static Vlan *vlan(); }; - } #endif /* _VLAN_H_ */