/* * \brief NIC driver to access Genode's nic service * \author Stefan Kalkowski * \date 2010-09-09 */ /* * Copyright (C) 2006-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. */ /* Linux includes */ #include #include #include #include #include #include #include #include #include #include #include #include static struct net_device *net_dev; static void FASTCALL genode_net_receive_packet(void* dev_addr, void *addr, unsigned long size) { struct net_device *dev = (struct net_device *) dev_addr; struct net_device_stats *stats = (struct net_device_stats*) netdev_priv(dev); /* allocate skb */ struct sk_buff *skb = dev_alloc_skb(size + 4); if (!skb) { if (printk_ratelimit()) printk(KERN_NOTICE "genode_net_rx: low on mem - packet dropped!\n"); stats->rx_dropped++; return; } /* copy packet */ genode_net_memcpy(skb_put(skb, size), addr, size); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); stats->rx_packets++; stats->rx_bytes += size; } /******************************** ** Network driver functions ** ********************************/ int genode_net_open(struct net_device *dev) { genode_net_start(dev, genode_net_receive_packet); netif_start_queue(dev); return 0; } int genode_net_close(struct net_device *dev) { netif_stop_queue(dev); genode_net_stop(); return 0; } int genode_net_xmit_frame(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = (struct net_device_stats*) netdev_priv(dev); int len = skb->len; void* addr = skb->data; /* collect acknowledgements of old packets */ while (genode_net_tx_ack_avail()) genode_net_tx_ack(); /* transmit to nic-session */ while (genode_net_tx(addr, len)) { /* tx queue is full, could not enqueue packet */ genode_net_tx_ack(); } dev_kfree_skb(skb); /* save timestamp */ dev->trans_start = jiffies; stats->tx_packets++; stats->tx_bytes += len; return 0; } struct net_device_stats* genode_net_get_stats(struct net_device *dev) { return (struct net_device_stats*) netdev_priv(dev); } void genode_net_tx_timeout(struct net_device *dev) { } static irqreturn_t event_interrupt(int irq, void *data) { genode_net_rx_receive(); return IRQ_HANDLED; } /************************** ** De-/Initialization ** **************************/ static const struct net_device_ops genode_net_dev_ops = { .ndo_open = genode_net_open, .ndo_stop = genode_net_close, .ndo_start_xmit = genode_net_xmit_frame, .ndo_get_stats = genode_net_get_stats, .ndo_tx_timeout = genode_net_tx_timeout }; /* Setup and register the device. */ static int __init genode_net_init(void) { int err = 0; unsigned irq; l4_cap_idx_t irq_cap; if (!genode_net_ready()) return 0; /* allocate network device */ if (!(net_dev = alloc_etherdev(sizeof(struct net_device_stats)))) goto out; net_dev->netdev_ops = &genode_net_dev_ops; net_dev->watchdog_timeo = 20 * HZ; /* set MAC address */ genode_net_mac(net_dev->dev_addr, ETH_ALEN); /** * Obtain an IRQ for the device. */ irq_cap = genode_net_irq_cap(); if ((irq = l4x_register_irq(irq_cap)) < 0) return -ENOMEM; if ((err = request_irq(irq, event_interrupt, 0, "Genode net", net_dev))) { printk(KERN_WARNING "%s: request_irq failed: %d\n", __func__, err); return err; } /* register network device */ if ((err = register_netdev(net_dev))) { panic("loopback: Failed to register netdevice: %d\n", err); goto out_free; } return 0; out_free: free_netdev(net_dev); out: return err; }; static void __exit genode_net_exit(void) { unregister_netdev(net_dev); free_netdev(net_dev); } module_init(genode_net_init); module_exit(genode_net_exit);