Sending via generic device works.
authorFlorian Pose <fp@igh-essen.com>
Thu, 15 Oct 2009 17:38:53 +0200
changeset 1541 26ac1c611100
parent 1540 49430a3fe73d
child 1542 91ae9c95dd2e
Sending via generic device works.
devices/generic.c
--- a/devices/generic.c	Tue Oct 13 17:56:32 2009 +0200
+++ b/devices/generic.c	Thu Oct 15 17:38:53 2009 +0200
@@ -45,6 +45,8 @@
 
 #define PFX "ec_generic: "
 
+#define ETH_P_ETHERCAT 0x88A4
+
 /*****************************************************************************/
 
 int __init ec_gen_init_module(void);
@@ -66,9 +68,7 @@
 typedef struct {
     struct list_head list;
     struct net_device *netdev;
-#if 0
-    struct net_device *real_netdev;
-#endif
+    struct socket *socket;
     ec_device_t *ecdev;
 } ec_gen_device_t;
 
@@ -130,9 +130,7 @@
     char null = 0x00;
 
     dev->ecdev = NULL;
-#if 0
-    dev->real_netdev = real_netdev;
-#endif
+    dev->socket = NULL;
 
 	dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup);
 	if (!dev->netdev) {
@@ -158,25 +156,69 @@
         ecdev_close(dev->ecdev);
         ecdev_withdraw(dev->ecdev);
     }
+    if (dev->socket) {
+        sock_release(dev->socket);
+    }
     free_netdev(dev->netdev);
 }
 
 /*****************************************************************************/
 
+/** Creates a network socket.
+ */
+int ec_gen_device_create_socket(
+        ec_gen_device_t *dev,
+        struct net_device *real_netdev
+        )
+{
+    int ret;
+    struct sockaddr_ll sa;
+
+    ret = sock_create_kern(PF_PACKET, SOCK_RAW, htons(ETH_P_ETHERCAT), &dev->socket);
+    if (ret) {
+        printk(KERN_ERR PFX "Failed to create socket.\n");
+        return ret;
+    }
+
+    printk(KERN_ERR PFX "Binding socket to interface %i (%s).\n",
+            real_netdev->ifindex, real_netdev->name);
+
+    memset(&sa, 0x00, sizeof(sa));
+    sa.sll_family = AF_PACKET;
+    sa.sll_protocol = htons(ETH_P_ETHERCAT);
+    sa.sll_ifindex = real_netdev->ifindex;
+    ret = kernel_bind(dev->socket, (struct sockaddr *) &sa, sizeof(sa));
+    if (ret) {
+        printk(KERN_ERR PFX "Failed to bind() socket to interface.\n");
+        sock_release(dev->socket);
+        dev->socket = NULL;
+        return ret;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
 /** Offer generic device to master.
  */
 int ec_gen_device_offer(
-        ec_gen_device_t *dev
+        ec_gen_device_t *dev,
+        struct net_device *real_netdev
         )
 {
     int ret = 0;
 
 	dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE);
     if (dev->ecdev) {
-        if (ecdev_open(dev->ecdev)) {
+        if (ec_gen_device_create_socket(dev, real_netdev)) {
+            ecdev_withdraw(dev->ecdev);
+            dev->ecdev = NULL;
+        } else if (ecdev_open(dev->ecdev)) {
             ecdev_withdraw(dev->ecdev);
             dev->ecdev = NULL;
         } else {
+            ecdev_set_link(dev->ecdev, 1); // FIXME
             ret = 1;
         }
     }
@@ -192,17 +234,7 @@
         ec_gen_device_t *dev
         )
 {
-    int ret = 0;
-
-#if 0
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
-    ret = dev->real_netdev->netdev_ops->ndo_open(dev->real_netdev);
-#else
-    ret = dev->real_netdev->open(dev->real_netdev);
-#endif
-#endif
-
-    return ret;
+    return 0;
 }
 
 /*****************************************************************************/
@@ -213,17 +245,7 @@
         ec_gen_device_t *dev
         )
 {
-    int ret = 0;
-
-#if 0
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
-    ret = dev->real_netdev->netdev_ops->ndo_stop(dev->real_netdev);
-#else
-    ret = dev->real_netdev->stop(dev->real_netdev);
-#endif
-#endif
-
-    return ret;
+    return 0;
 }
 
 /*****************************************************************************/
@@ -233,7 +255,18 @@
         struct sk_buff *skb
         )
 {
-    return 0;
+    struct msghdr msg;
+    struct kvec iov;
+    size_t len = skb->len;
+    int ret;
+
+    iov.iov_base = skb->data;
+    iov.iov_len = len;
+    memset(&msg, 0, sizeof(msg));
+
+    ret = kernel_sendmsg(dev->socket, &msg, &iov, 1, len);
+
+    return ret == len ? NETDEV_TX_OK : NETDEV_TX_BUSY;
 }
 
 /*****************************************************************************/
@@ -258,7 +291,7 @@
         return ret;
     }
 
-    if (ec_gen_device_offer(gendev)) {
+    if (ec_gen_device_offer(gendev, netdev)) {
         list_add_tail(&gendev->list, &generic_devices);
     } else {
         ec_gen_device_clear(gendev);