]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/ankh/server/netlib/linux_glue.c
Inital import
[l4.git] / l4 / pkg / ankh / server / netlib / linux_glue.c
diff --git a/l4/pkg/ankh/server/netlib/linux_glue.c b/l4/pkg/ankh/server/netlib/linux_glue.c
new file mode 100644 (file)
index 0000000..0b347b0
--- /dev/null
@@ -0,0 +1,184 @@
+#include <linux/netdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include "linux_glue.h"
+
+#include <l4/dde/linux26/dde26_net.h>
+#undef __always_inline
+#include <assert.h>
+
+#define DEBUG(DBG, msg, ...) \
+       do { if (DBG) \
+                       printk(msg, ##__VA_ARGS__); \
+       } while (0);
+
+#define ANKH_DEBUG_INIT     1
+#define ANKH_DEBUG_PACKET   0
+
+int ankh_debug_linuxglue = 0;
+void ankh_set_debug()   { ++ankh_debug_linuxglue; }
+void ankh_unset_debug() { --ankh_debug_linuxglue; }
+
+/*****************************************************************************
+ * Open the "real" network devices. Return the number of opened interfaces.
+ *****************************************************************************/
+int open_network_devices(int promisc)
+{
+       struct net_device *dev;
+       struct net *net;
+       int err = 0, cnt = 0;
+
+       DEBUG(ANKH_DEBUG_INIT, "%s() \n", __func__);
+
+       for_each_net(net) {
+               for_each_netdev(net, dev)
+               {
+                       DEBUG(ANKH_DEBUG_INIT, "opening %s\n", dev->name);
+
+                       // beam us to promiscuous mode, so that we can receive packets that
+                       // are not meant for the NIC's MAC address --> we need that, because
+                       // ORe clients have different MAC addresses
+                       if (promisc && netdev_set_promisc(dev) == 0)
+                                       DEBUG(ANKH_DEBUG_INIT, "set interface to promiscuous mode.\n");
+
+                       err = dev_open(dev);
+                       if (err)
+                       {
+                               DEBUG(ANKH_DEBUG_INIT, "error opening %s : %d\n", dev->name, err);
+                               return err;
+                       }
+                       else // success
+                               netdev_add(dev);
+
+               cnt++;
+               //xmit_lock_add(dev->name);
+               }
+       }
+
+       return cnt;
+}
+
+
+static int net_recv_irq(struct sk_buff *skb)
+{
+       int i;
+       
+       /*
+        * Special case: The loopback device is handled
+        * by local packet delivery beforehand. The loopback
+        * driver however, tries to directly call the recv() routine
+        * upon xmit(), too.
+        */
+       if (!strcmp(skb->dev->name, "lo"))
+               return NET_RX_SUCCESS;
+
+       /*
+        * Push eth header back, so that skb->data is the raw packet.
+        */
+       skb_push(skb, skb->dev->hard_header_len);
+
+       /*
+        * Hand to upper layers.
+        */
+#if 0
+       DECLARE_MAC_BUF(mac);
+       printk("%s\n", print_mac(mac, skb->data));
+#endif
+       packet_deliver(skb->data, skb->len, skb->dev->name, 0);
+
+       /*
+        * Need to release skb here.
+        */
+       kfree_skb(skb);
+
+       return NET_RX_SUCCESS;
+}
+
+
+static void _init_linux_glue(void)
+{
+       l4dde26_softirq_init();
+       skb_init();
+
+       l4dde26_register_rx_callback(net_recv_irq);
+}
+subsys_initcall(_init_linux_glue);
+
+/*****************************************************************************
+ * wrapper functions for accessing net_device members
+ *****************************************************************************/
+
+#define ND(p) ((struct net_device *)p)
+
+int netdev_irq(void *netdev)
+{ return ND(netdev)->irq; }
+
+
+char const *netdev_name(void *netdev)
+{ return dev_name(&ND(netdev)->dev); }
+
+
+int netdev_set_promisc(void *netdev)
+{
+       int err;
+       struct net_device *dev = ND(netdev);
+       if ((err = dev_change_flags(dev, dev->flags | IFF_PROMISC)) != 0)
+               DEBUG(ANKH_DEBUG_INIT, "%s could not be set to promiscuous mode.\n",
+                                     dev->name);
+
+       return err;
+}
+
+
+int netdev_unset_promisc(void *netdev)
+{
+       int err;
+       struct net_device *dev = ND(netdev);
+       if ((err = dev_change_flags(dev, dev->flags & ~IFF_PROMISC)) != 0)
+               DEBUG(ANKH_DEBUG_INIT, "%s could not be set to promiscuous mode.\n",
+                                     dev->name);
+
+       return err;
+}
+
+
+void *alloc_dmaable_buffer(unsigned size)
+{
+       return kmalloc(size, GFP_KERNEL);
+}
+
+
+int netdev_get_promisc(void *netdev)
+{ return ND(netdev)->flags & IFF_PROMISC; }
+
+
+char *netdev_dev_addr(void *netdev)
+{ return ND(netdev)->dev_addr; }
+
+
+int netdev_mtu(void *netdev)
+{ return ND(netdev)->mtu; }
+
+
+int netdev_xmit(void *netdev, char *addr, unsigned len)
+{
+       // XXX could we pass 0 as length here? data netdev is set
+       //     below anyway
+    struct sk_buff *skb = alloc_skb(len, GFP_KERNEL);
+    assert(skb);
+
+    skb->data = addr; // XXX
+    skb->len  = len;
+    skb->dev  = ND(netdev);
+
+    while (netif_queue_stopped(ND(netdev)))
+               msleep(1);
+
+    int err;
+    if (ND(netdev)->netdev_ops)
+        err = ND(netdev)->netdev_ops->ndo_start_xmit(skb, ND(netdev));
+    else
+        err = ND(netdev)->hard_start_xmit(skb, ND(netdev));
+
+    return err;
+}